Hatena::ブログ(Diary)

いちいの日記 このページをアンテナに追加 RSSフィード

2012/02/03(Friday)

[] mysqlbinlog なんてやめて show binlog events を使おう

夜中に眠いのに 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 がある、と。

[] おや?

https://twitter.com/#!/nslope/status/164802160524136448

なんかひっそりと Solaris11 のソースが公開されてるのかな?? あんまり「キタ━(゚∀゚)━!」と盛り上がってないけど...。

とりあえず du.c 探したけど見つかんない。 2 つめの zipcoreutils や ./osnet/usr/src/lib/libcmd/common/find.c とかは見つかったが。

[追記] まあ

https://twitter.com/#!/syoyo/status/165142247371845632

前からあったらしいですorz

[solaris][zfs][memo] compression と recordsize

Solaris 11 11/11 (5.11 11.0) での話。

中身は MySQL の MYD と MYI と frm です。やっぱ InnoDB とか忘れて、基本は bs=128k で生きてたほうが良いような気がする。

send/receive と rsync を状況に合わせて使い分ける場合、 recordsize を設定してたのを忘れてメンテナンス後に変わっちゃう危険があるので、ちまちま分けたくはない。なので公約数的な値を取りたいわけですが、 16k にするかどうかくらいは意識して分けておいたほうがいいかな。

% for i in 2 3 4; do time rsync -av --progress test1/* test$i >/dev/null; done
rsync -av --progress test1/* test$i  83.51s user 57.11s system 103% cpu 2:16.36 total
rsync -av --progress test1/* test$i  87.93s user 58.11s system 100% cpu 2:25.67 total
rsync -av --progress test1/* test$i  79.15s user 49.77s system 99% cpu 2:09.13 total
% zfs list -o space,recordsize,compression,compressratio -r tank
NAME        AVAIL   USED  USEDSNAP  USEDDS  USEDREFRESERV  USEDCHILD  RECSIZE  COMPRESS  RATIO
tank        20.8T  26.5G         0    123K              0      26.5G     128K       off  1.28x
tank/test1  20.8T  8.09G         0   8.09G              0          0     128K       off  1.00x
tank/test2  20.8T  4.45G         0   4.45G              0          0     128K        on  1.82x
tank/test3  20.8T  8.77G         0   8.77G              0          0      16K       off  1.00x
tank/test4  20.8T  5.15G         0   5.15G              0          0      16K        on  1.76x
tank/test5  20.8T  8.05G         0   8.05G              0          0       1M       off  1.00x [追記]
tank/test6  20.8T  4.37G         0   4.37G              0          0       1M        on  1.84x [追記]

cf. http://www.c0t0d0s0.org/archives/5865-SSD,-ZFS,-L2ARC-and-mysql.html

du

余談ですが、 /usr/bin/du のオプション無しって何を表示してるんだろ?

それ以外については、ファイルサイズの合計ではなく、そのディレクトリ以下に含まれるファイルたちの disk usage を出してくれてるみたい。

% /usr/bin/du test*   
16957022        test1
9331071         test2
18395314        test3
10803173        test4
% /usr/bin/du -h test*
 8.1G   test1
 4.4G   test2
 8.8G   test3
 5.2G   test4
% /usr/gnu/bin/du test*
8478511 test1
4665536 test2
9197657 test3
5401587 test4
% /usr/gnu/bin/du -h test*
8.1G    test1
4.5G    test2
8.8G    test3
5.2G    test4