スレーブへのレプリケーションのタイムラグを解消

昨夜、Webアプリに対するリクエスト数が急激に増大し、MySQLのスレーブに対するレプリケーションのタイムラグがみるみる増加し、アプリケーションロジック上のエラーが頻発するようになってしまった。

一昨日のピークが秒間300リクエストちょい、昨日が800超え。。。おそるべし、ソーシャルアプリ。

cacti で見ていたタイムラグの単位が、てっきりミリ秒だと思ってたら、実は秒だったことが発覚して、青ざめた。
遅延が2秒になっちゃったよ、やべーよ、と話していたら、実は2,000秒だった罠。。。orz
オワットル。ひさびさにシビれた。。。

実践ハイパフォーマンスMySQLに助けを乞うと、「 8.7.14 レプリケーションの過度の遅延」というまさにぴったりの項目があり、とにかくスレーブに余計な仕事をさせるな、とのお達しが。ディスクのIOWaitが結構あったので、ディスクへのIOを減らす目的で、本で紹介されていたコミット時のディスクへのフラッシュの間隔を設定する innodb_flush_log_at_trx_commit の値を変更してみた。
innodb_flush_log_at_trx_commit のデフォルト値の 1 だとcommit時に毎回ディスクへ書き込むが、2 にすると、1秒ごとに書き込むようになる。
つまり、commitが頻繁に発生しているような環境では大幅にディスク書き込みの頻度を減らせる。が、代わりに障害時に最悪1秒間のデータロスが発生する危険性がある。
でも、スレーブじゃん。データ壊れたっていいぢゃん。ということで採用。
# ただし、マスタに昇格する際には、忘れずこの値をデフォルトに戻す必要アリ

mysql> set global innodb_flush_log_at_trx_commit=2

ネ申降臨。。。

2,000数百あったタイムラグの値がみるみる数十単位で減っていく。気持ちイイ。
2,3分でタイムラグがゼロに!!!
マスタとスレーブの同期遅延によるアプリケーション上のエラーもなくなり、メデタシメデタシ。

なお、スレーブの状態を見るには以下のコマンドが便利。

mysql> show slave status \G

項目の見方はマニュアルを。
ちなみに、タイムラグは Seconds_Behind_Master という項目です。

あと、本で紹介されていた方法で、スレーブ上でそもそもバイナリログを書かなくするために innodb_locks_unsafe_for_binlog を 1 に設定する、というのもあったのでそれも有効だと思う。今回はそこまでしなくても大丈夫になっちゃったので見送ったけど、またレプリケーションの遅延が発生したら試してみよう。