September 13, 2013 By Stephane Combaudon
日々、Percona Remote DBAの顧客とやり取りをしていると、時々、MySQLのレプリケーション遅延が0とX(ある値)の間を継続的に行ったり来たりする現象に直面する。例えば、Seconds_Behind_Masterが数秒間0で、その後6287とか25341といった値になり、また0に戻り…といったように。この記事で、ある場合は目に見え、ある場合は見えないようなこういった現象の5つのシナリオと現象を書こうと思う。
1. 複数のスレーブでのserver-idの重複
現象 : スレーブのエラーログに、スレーブスレッドがマスタへの接続・切断を繰り返していると記録されている。
解決法 : レプリケーションしているノード全てがユニークなserver-idを持っているか確認する。
2. デュアルマスタの環境で"log_slave_updates"が有効になっていてserver-idが変わってしまう
現象 : 1台目のマスタのMySQLを停止した後、2台目も停止。その後何らかの作業やメンテナンスを実行したあなたは、server-idを新しいIPアドレスの末尾の番号と合わせた方がいいんじゃないかということに気づく。そして全てオンラインに戻した後に、log_slave_updatesが有効になっているせいで、2台のマスタ間で一部のバイナリログがぐるぐる循環するという奇妙な現象に出くわす。新しいserver-idは違うのになぜ?これは、最初のマスタが既に停止している状態で2台目のマスタのシャットダウン前に書かれたデータが、再起動後のどちらのマスタにも自分のデータではないと認識されてしまうためだ。そのため、バイナリログを適用してレプリケーション先のサーバに転送するが、転送先のserver-idとバイナリログに書かれたserver-idが一致せず、無限ループになってしまう。
解決法 : 片方のマスタでスレーブのポジションをリセットし、"幽霊化した"バイナリログが循環するのを止める。
3. MySQLのオプション "sync_relay_log", "sync_relay_log_info", "sync_master_info"
現象 : SHOW SLAVE STATUS
の出力によると、ある時はスレーブスレッドが遅延を含んでイベントをキューイングしており、ある時は遅延0秒を示している一方で、実際のマスタのポジションを見ると、遅延はX秒になるはずなのにそうなっていない。あるいは、IOが限界に達していたりディスクへのIOPSが非常に高いような現象なのに、pt-diskstatsで確認するとディスクは50%ほどしかアクセスされていない。私の経験では、マスタでは1500IOPSなのに、スレーブでは10倍、15000IOPSのアクセスが来ており、同じく60%ぐらいアクセスされている状態ということがあった。この状況を見ると、行ベースのレプリケーション(binlog_format=ROW)を使っており、マスタには継続的な更新がかかっていると思うかもしれないが、どうして遅延が跳ねてしまい、ディスクIOは高いにしても限界に達しはしないのだろうか?
可能性 : イベントごとにデータをディスクに同期するためのオプションである、sync_relay_log、sync_relay_log_info、sync_master_infoを有効にしていないか確認しよう。例えば、sync_relay_logは、オートコミットが有効になっていると、ステートメントごとにリレーログに書き込みを行い、そうでなければトランザクションごとに書き込みを行う。これらのオプションを有効にすると、同期を高速にするバッテリバックアップされたキャッシュ付きのディスクを使っているのでない場合は、システムは遅くなってしまう。
4. ネットワークの遅延
現象 : マスタとスレーブの間のネットワークが貧弱。帯域不足のネットワークだと、スレーブのIO_threadはマスタに追いつくのが難しくなる。SQLスレッドは、IO_threadがイベントを保存するのを待っている間は遅延0を示す。IO_threadがリレーログに書き込みを始めると、SQL_threadはXXX秒遅延、と表示を始める。
解決策 : ネットワークのスループットを調べる。
5. コミットの遅いトランザクション
現象 : トランザクションをマスタで実行し、その後何らかの理由(アプリケーションのバグやフロントエンドの問題など)でコミットが遅くなると、スレーブでのレプリケーション遅延となる。例えば、コミットまで1時間かかると、トランザクションが実行されている間、スレーブでは3600秒の遅延と表示される。
解決策 : レプリケーションの遅延をモニタリングする、pt-heartbeatを使おう。