せじまくんの刺さらない話(MySQL Slave増設編)
はじめまして。プラットフォーム開発本部のせじまです。好きなものはDisk I/Oです。
今回はMySQL(on Linux)のレプリケーションにまつわる、ちょっとしたお話をさせていただきたいと思います。
はじめに
MySQL4.0以降のレプリケーションは、
- Masterのmysqldが、INSERT/UPDATE/DELETEなどの更新情報を、バイナリログに記録する。
- Slaveのmysqld(IOスレッド)は、masterのmysqldに接続し、バイナリログを転送する。
- Slaveのmysqld(IOスレッド)は、受信したバイナリログ内容を、リレーログに記録する。
- Slaveのmysqld(SQLスレッド)は、リレーログを読み込み、更新内容をslaveのDBに反映する。
といった仕組みになっています。図にすると次の通りです(*1)。
MySQLのレプリケーションはとても良くできた仕組みなのですが、グリーではある問題を抱えていました。稼働中のMasterにSlave を増設するとき、Masterが刺さってしまう(*2)ことがあったのです。問題は、Masterのバイナリログの転送にありました。
Masterを停止させずにSlaveを増設する場合、
- ファイルシステム等の機能を利用して、既存のDBのスナップショットをとる
- 既存のSlaveを一時停止して、新しいSlaveに、データをまるまるコピーする
いずれかの方法で増設するSlaveにデータをコピーして、レプリケーションを開始することが一般的だと思います。ただ、スナップショットをとったりデータをコピーしている間もMasterのバイナリログは更新され続けています。更新頻度が高い == バイナリログを大量に吐くMasterに対してSlaveを増設したとき、
- Masterの古いバイナリログがページキャッシュ上に載っておらず、Slaveに転送する際、Disk Readが多発してしまう。
- バイナリログの転送で、ネットワークの帯域を食われてしまう。
といった問題が起こりえます。
特に、バイナリログの転送に伴う突発的なDisk Readは、致命的な問題といえます。
基本的に、Diskへのwriteはバッファリングないしスケジューリングの余地があります。しかし、(キャッシュに載ってない)readは、Diskからの応答を待つしかありません。read の IOPS が高くなると MySQL はわりと容易に刺さるので、私はMySQLの負荷を見るとき、write の IOPS よりも read の IOPS を気にすることが多いです。(*3)
どうするか
今回は次のような対処を行いました。
-
max_binlog_size のデフォルト(1GB)は大きすぎるので、小さくする。
- バイナリログがページキャッシュを何GBも使わないでほしい
- バイナリログの読み込みは sequential read になるとはいえ、一度に1GBもreadしたくない
- 増設対象のSlaveで実行するスクリプトを作成。疑似コードは次の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
while (slaveに最新のバイナリログが転送されるまで) { while (バイナリログ一個分転送するまで) { master に ssh 経由で load average チェックして、高ければ下がるまで待つ sudo ionice -c2 -n7 cat ${binlog} > /dev/null # IOスレッドが転送するバイナリログだけを、強制的にページキャッシュに載せる slaveで START SLAVE; sleep STOP SLAVE IO_THREAD; # バイナリログの転送より、クエリを実行する方が遥かに時間かかるので、SQLスレッドは停止しない。 sleep # 他のslaveへのバイナリログ転送を阻害しないよう、 idle する } 転送されたバイナリログのクエリを、SQLスレッドが実行し終わるまで待つ } |
ionice は I/O scheduler が cfq じゃないと効果ないです。
さいごに
つまるところ、
- ionice cat ${binlog}
- バイナリログをちょっとずつ転送
- バイナリログ一個分転送できたら、IOスレッド止めて、転送したバイナリログのクエリを実行
- 1. にもどる
を繰り返すだけのお粗末な対応ですが、これがなかなか効き目ありました。
かつては、vmstat等でMasterの負荷を見ながら手動でSTOP SLAVE && START SLAVE を叩いて、少しずつSlave増設していたこともありましたが、いまではピークタイムのSlave増設が危なげなく行えるようになりました。また、一台のMasterに対して、複数台のSlaveを同時に追加したりもできています。
今回のお話が皆様の参考になればさいわいです。
これからもGREE Engineers’ Blogをよろしくおねがいします!
*1: 奥野幹也 氏の『エキスパートのためのMySQL[運用+管理]トラブルシューティングガイド』P.321の図を参考にさせていただきました
*2: ささる(動詞)「コマンドやネットワークが過負荷等の要因で無反応状態になること。」~グリー社内用語集より
*3: 特に、バッテリーバックアップ付きのRAID装置を使っている場合、writeのIOPSは目覚ましい向上を見せるので、readの方が先に性能限界に達してしまう印象があります。