夜中に眠いのに master のディスク容量がいっぱいで、でも binlog 用のスペースがない slave たちはまだ明日起きてから対応するんでも間に合うとき。よくありますよね。
- ほっといてエラーになるよりかはその場しのげる方がマシ
- 多少サービス止めるなり i/o 負荷が高くてもいいから何とかしたい
- 根本的には master 切り替えるしかない
- だが、そこまで元気がない
そんなとき、いままで mysqlbinlog と格闘しながら pos のコピペに注意しつつやってたんですが、 show binlog events という便利コマンドがあることを今更知ったメモです。
基本的な方針
master から絶対に読み込みがないデータを消して、延命することにします。しかし innodb だったりするので単に delete しても容量は減りません。
そこで、えいやとアプリを止めて (or table lock して) 以下のようにすることにします。
CREATE TABLE hoge_history_new LIKE hoge_history; INSERT INTO hoge_history_new SELECT * FROM hoge_history WHERE date >= '2012-01-01'; RENAME TABLE hoge_history TO hoge_history_bak, hoge_history_new TO hoge_history; DROP TABLE hoge_histroy_bak;
ほんとに無停止でやりたいなら trigger で hoge_history_new に double write するとか。しかし trigger 仕込むのでミスするくらいなら、停止した上で停止時間短い方針考えるほうがいい時もあるかかも。
slave は drop してほしくない
これでなんとか master は 10 分停止くらいで drop したぶんの容量が稼げた。しかし slave はまだ容量に多少余裕あるので、できたらこんな drop して欲しくない。と言うよりデータ消しちゃだめじゃん!!
なので、データ消さない slave を 1 つ狙いを定め、上の sql を流す直前に master で show master status を実行し確認した pos まで replication を進めて止めておきます。
slave> STOP SLAVE; slave> START SLAVE UNTIL master_log_file='hoge-bin.000123', master_log_pos=456789;
drop table だけ skip しよう
さて、次は drop table の直前まで replication を進めた上で stop slave し、 sql_slave_skip_counter=1 して drop だけ飛ばしてやりたい。
こんなとき、 pos をどこまで進めればいいかを今までは mysqlbinlog コマンドで調べていました。しかし以下の理由で、絶対もっといい方法あんだろ、と思っていた。
- pos が境界の意味でどっちに含まれているのかよくわからん
- skip_counter は event 単位で、 pos との対応が明確でない
- だいたい出力多すぎで夜中にやると絶対ミスる
なんでドキュメントぷらぷら眺めてたら show binlog events という最強に見やすいコマンドがあったんですね!
つかいかた
まずは slave が何処まで replication しているか調べます。この例では pos=456789 の位置まで実行済み、ということになります。
slave> SHOW SLAVE STATUS\G ... Master_Log_File: hoge-bin.000123 ... Exec_Master_Log_Pos: 456789
次に pos=456789 からのイベント内容を master で調べます。
master> SHOW BINLOG EVENTS IN 'hoge-bin.000123' FROM 456789 LIMIT 2; +-----------------+--------+------------+-----------+-------------+----------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | +-----------------+--------+------------+-----------+-------------+----------------------------------------+ | hoge-bin.000123 | 456789 | Query | 100 | 456901 | use `aho`; drop table hoge_history_bak | | hoge-bin.000123 | 456901 | Intvar | 100 | 457005 | INSERT_ID=91187051 | +-----------------+--------+------------+-----------+-------------+----------------------------------------+ 2 rows in set (0.00 sec)
お、なんとも運がいいことにちょうど次のイベントが drop になってるじゃないですか! ということで slave で 1 イベントをスキップすれば ok。
slave> SET GLOBAL sql_slave_skip_counter=1 slave> START SLAVE;
これで、めでたく master だけデータが欠損した状態に出来ました。後はちゃんと寝てからこの slave に孫を作ってそのまま master に昇格させればよい。
pos と event
改めて考えてみれば、 pos は境界の場所であって、そこに対応する event があるわけじゃないんだよね。
1234567890123456789012345678901234567890 | event1 | event2 | event3 | ^pos=1 ^pos=10 ^pos=25 ^pos=40
たとえば pos=10 のときに 10 に対応する event はなく、前に event1 があって後ろに event2 がある、と。