MySQLでのちょっとしたTIPS(slave追加の際のトラフィック)

こんにちは。伊達直人さんから贈り物のこないiwanagaです。ランドセルじゃなくてMacBook Airが欲しいです。

昨年書いた「ソーシャルゲームのためのMySQL入門」は嬉しいことにご好評を頂き感激しております。 僕自身も1000はてブ超えたことは無かったので感無量です。その2は鋭意執筆中ですので お楽しみにしておいて下さい。

さて、今日はそんなに重くない感じで最近使ったちょっとしたTIPSをシェアしたいと思います。 最低限の努力でもまぁそれなりの解決方法ってのはあるんだなという感じで聞いて頂ければと思います。

slave追加の際に注意すること

MySQLと言えばレプリケーションですが、高トランザクション環境でslaveを追加するには 簡単にmasterを止められないので一工夫必要です。DeNAでは各所で紹介していますが、 mysqldumpを取るためにサービス参照のないslave(通称backup)を設置して、 そこで静止断面とその時のmasterのbinlogのポジションをshow slave statusを使って保存しています。

こうしておけば、slaveを追加したいと思った時にはまず静止断面としてのmysqldumpを流しこんで、 保存しておいたmasterのポジションに向けてchange masterしてstart slaveするだけで、 後は待っていればレプリをキャッチアップしてslave作成完了となります。

ただ、このstart slaveしたあとにbinlogをキャッチアップする際にmasterで問題が起こることがあります。

  1. binlog転送は全力で行われるのでmasterのoutのtrafficが枯れる
  2. OSのfilecacheにないのでmasterのread IOが出てしまう(参考:GREE Engineers' Blog)

2についてはグリーさんのブログに詳しいのでそちらを見て頂くとして、ここでは1についてTIPSを。

ネットワークインタフェースを潤沢なモノにしておけばトラフィックが枯れることは あまりないと思いますが、古い環境だとたまに帯域が狭いところがあったりして start slaveした瞬間にmasterのトラフィックが頭打ちになり、サービスのレスポンスが遅くなることが あったりします。ってかしました。

この問題に対してMySQL側からのアプローチは現状存在しないため、考えられる対応は以下になります。

  1. binlogをscp/rsyncで帯域制御して送って、mysqlbinlogを使ってslaveに適応し、適当なところへchange master
  2. slave側でstop slave/start slaveをこまめに実行して平均トラフィックを下げる
  3. Linux側で帯域制御する(cbq)

1がかっこいい感じなんですが、結構面倒です。まず、binlogのどこから適応させるかを先ほどの show slave statusの結果を元にmysqlbinlogstart-positionオプションで与えつつ、 適応させたいbinlogを全て引数に与えて1コマンドで実行する必要があります。

mysqlbinlog --start-position = 111111 mysqld-bin.000001 mysqld-bin.000002 mysqld-bin.000003 \
    | mysql -uroot -p database

これが終わったらmysqld-bin.000004の先頭に向けてchange masterすれば多少は最新に近づけてから start slaveできますね。

3については実現性まで検討してないんですが、ソフトウェア的に帯域制御してしまってmasterの トラフィックを使い過ぎないというアプローチです。ちゃんとしたソースを調べたわけではないですが cbqは自分から送るトラフィックしか制御できないらしいので、本件で利用するのであれば masterでslaveのポートへの通信を制御するしかなさそうです。 (新しめのカーネルだと受信側も制御できるという噂もききました)

ただ、今回時間がなかったので、一番お手軽な2の手段を取りました。熟考の末に僕があみ出した スクリプトはこれだ!どうだ!

while : ;
do
    echo "`date` stop slave"; mysql -uroot -pxxxx -e "stop slave io_thread";
    sleep 5;
    echo "`date` start slave"; mysql -uroot -pxxxx -e "start slave io_thread";
    sleep 1;
done

はい、誰でもおもいつくしょぼしょぼスクリプトですね。

slaveではsql_threadは走らせっぱなしにしておきます。io_threadの起動時間は あまり長くすると思ったよりトラフィックを使ってしまうので、 このぐらいが良さそうな感じでした。実際、これでサービスに影響与えることなく無事slave追加できました。

今回重要視して欲しいのは、起きてる問題に対して最小限のリソースで解決したという辺りです。 slaveの追加なんてさすがに1日に何十回も起きる作業じゃないのですごい頑張ってcbq調べたり、 (僕は)慣れていないmysqlbinlogでのログの適応とかをやらずに、いつもこなれた管理コマンドの組み合わせで 結果としては十分な結果が得られました。

というわけで、このぐらいレベルの低い記事を書いておけば、きっと他の記事の見栄えがよくなるはずです。 次はすばらしいエントリを誰かが書いてくれるとおもいますのでお楽しみに!

ツイート
シェア
あとで読む
ブックマーク
送る
メールで送る