2014年5月15日木曜日

pt-table-checksumでレプリケーション不整合を確認する

わたしはレプリケーション(と、バイナリーログ)フィルターが嫌いです。

フィルターが評価されるルール が理解されないまま運用されてカレントデータベースがNULLのままUPDATEを実行したりする人がいたりするので嫌なんですが、ストレージとかスレーブの性能とかネットワークの帯域とかで使わなければならないことも多々あります。

そんな時によく使う、 pt-table-checksum のメモ。

$ pt-table-checksum --socket /usr/mysql/5.6.17/data/mysql.sock --user root --password xxxx --tables d1.t1,d1.t2,d2.t1 --replicate test.pt-tcs --create-replicate-table
            TS ERRORS  DIFFS     ROWS  CHUNKS SKIPPED    TIME TABLE
05-15T17:36:00      0      0    39028       4       0   0.289 d1.t1
05-15T17:36:01      0      0   173469       4       0   0.239 d1.t2
05-15T17:36:14      0      0  5105937      15       0   7.264 d2.t1

こんなふうにマスターで流すと、


# at 108042433
#140515 17:36:00 server id 33597  end_log_pos 108043217 CRC32 0x0ca8897e        Query   thread_id=420836        exec_time=0
     error_code=0
use `test`/*!*/;
SET TIMESTAMP=1400142960/*!*/;
CREATE TABLE IF NOT EXISTS `test`.`pt-tcs` (
     db             char(64)     NOT NULL,
     tbl            char(64)     NOT NULL,
     chunk          int          NOT NULL,
     chunk_time     float            NULL,
     chunk_index    varchar(200)     NULL,
     lower_boundary text             NULL,
     upper_boundary text             NULL,
     this_crc       char(40)     NOT NULL,
     this_cnt       int          NOT NULL,
     master_crc     char(40)         NULL,
     master_cnt     int              NULL,
     ts             timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
     PRIMARY KEY (db, tbl, chunk),
     INDEX ts_db_tbl (ts, db, tbl)
  ) ENGINE=InnoDB
/*!*/;
..
# at 108043627
#140515 17:36:00 server id 33597  end_log_pos 108044746 CRC32 0x0a0d40d3        Query   thread_id=420836        exec_time=0
     error_code=0
SET TIMESTAMP=1400142960/*!*/;
REPLACE INTO `test`.`pt-tcs` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT 'd1', 't1', '1', 'PRIMARY', '1', '1000', COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `column1`, `column2`, ..,)) AS UNSIGNED)), 10, 16)), 0) AS crc FROM `d1`.`t1` FORCE INDEX(`PRIMARY`) WHERE ((`column1` >= '1')) AND ((`column1` <= '1000')) /*checksum chunk*/
/*!*/;
..
# at 108044864
#140515 17:36:00 server id 33597  end_log_pos 108045097 CRC32 0x4799fdd5        Query   thread_id=420836        exec_time=0
     error_code=0
SET TIMESTAMP=1400142960/*!*/;
UPDATE `test`.`pt-tcs` SET chunk_time = '0.011250', master_crc = '4173135a', master_cnt = '1000' WHERE db = 'd1' AND tbl = 't1' AND chunk = '1'
/*!*/;
..

とまあこんな感じで、チェック対象のテーブルに入っている値をハッシュ計算してテーブルに入れ込んでくれます。

このREPLACE INTOやUPDATEはスレーブにも伝播され、スレーブ側で再実行(スレーブのテーブルに本当に入っている値をハッシュ計算してテーブルに入れ込む)されるので、スクリプトが流れ終わったあとにマスターとスレーブのこのテーブル(test.pt-tcs)の中身を比較してやれば、同じデータが入っているであろうことが判断できます。

pt-tcsを実行するサーバーからログインできるユーザーがいれば、pt-tcsの中でも直接比較してexit codeとかに反映してくれるようなことも書いてありますし、PMPを入れ込めば、この値に差分がないかどうかを定期的にNagiosから確認できたりもするようです。

http://www.percona.com/doc/percona-monitoring-plugins/1.1/nagios/pmp-check-pt-table-checksum.html


弱点は、RBRの環境下では使えないこと。マスターで計算されたハッシュ値がそのままスレーブに渡されてしまうので、意味を為さなくなってしまう。

が、PXC(Galera Cluster)でも使えるようなことが書いてあって、どうやって計算しているのだろう。SET SESSION binlog_format= STATEMENTを押し込むのかな?

0 件のコメント :

コメントを投稿