2015年4月1日水曜日

pt-online-schema-change(と、pt-table-checksumとかもろもろ)の--recursion-methodについて

pt-online-schema-change(以下、pt-osc)をはじめとするPercona Toolkitのツール群には、--recursion-methodというオプションがあります。

pt-online-schema-change — Percona Toolkit Documentation


暗黙のデフォルトは"processlist,hosts"で、なんとなくprocesslist(SHOW PROCESSLISTからBinlog Dump Threadのホスト名を引っ張り挙げる)とhosts(SHOW SLAVE HOSTSの結果からホスト名とポート番号を引っ張り挙げる)をよしなにミックスしてくれそうな雰囲気なれど。

これ残念ながら単にprocesslistだけ指定した時と同じ結果になります。

( ´-`).oO(全くトリアージされる気はしないけど、一応ばぐれぽも上げた
Bug #1438641 “Default value of --recursion-method, “processlist,...” : Bugs : Percona Toolkit

まあそれはいいとして、各--recursion-method個別の動作。動作環境は127.0.0.1:64057に5.7なマスター, 127.10.0.1:64056 に5.6なスレーブがぶら下がっている。


* processlist

$ PTDEBUG=1 pt-online-schema-change --execute --alter "Engine = InnoDB" h=127.10.0.1,D=d1,t=t1,u=root,P=64057 --recursion-method=processlist
..
# MasterSlave:4031 30199 Recursion methods: processlist
# MasterSlave:4041 30199 Connected to D=d1,P=64057,h=127.0.0.1,t=t1,u=root
# MasterSlave:4050 30199 SELECT @@SERVER_ID
# MasterSlave:4052 30199 Working on server ID 1057
# MasterSlave:4085 30199 Looking for slaves on D=d1,P=64057,h=127.0.0.1,t=t1,u=root using methods processlist
# MasterSlave:4092 30199 Finding slaves with _find_slaves_by_processlist
# MasterSlave:4154 30199 DBI::db=HASH(0x3051a08) SHOW GRANTS FOR CURRENT_USER()
# MasterSlave:4184 30199 DBI::db=HASH(0x3051a08) SHOW PROCESSLIST
..
# MasterSlave:4097 30199 Found 1 slaves
..
# MasterSlave:4041 30199 Connected to D=d1,P=64057,h=127.10.0.1,u=root
# MasterSlave:4050 30199 SELECT @@SERVER_ID
# MasterSlave:4052 30199 Working on server ID 1057
# MasterSlave:4058 30199 Server ID seen, or not what master said
..

mysql57> show processlist;
+----+------+------------------+------+------------------+------+----------------+------------------+
| Id | User | Host             | db   | Command          | Time | State          | Info             |
+----+------+------------------+------+------------------+------+----------------+------------------+
| 39 | root | 127.10.0.1:45008 | NULL | Binlog Dump GTID |  112 | Writing to net | NULL             |
| 46 | root | localhost        | NULL | Query            |    0 | starting       | show processlist |
+----+------+------------------+------+------------------+------+----------------+------------------+
2 rows in set (0.02 sec)

SHOW PROCESSLISTの結果からCommand =~ /Binlog Dump/なスレッドのHost部からホスト名を引いている。それ以外のパラメーターはもともとマスターに接続するために指定したDSN(h=127.0.0.1,D=d1,t=t1,u=root,P=64057)を流用するらしい。
なので、IPアドレスは127.10.0.1向きになっているけどポート番号がそのまま。

というわけで、
  * マスターに接続するDSNに明示的にポートを指定している場合で
    * スレーブでポート番号が違う場合
  * マスターに接続するDSNに明示的にポートを指定していない場合(S= でソケットを指定しているとか)で
    * スレーブが標準ポート(3306)以外を使っている場合
はprocesslistではスレーブの自動検出に失敗する。


* hosts

$ PTDEBUG=1 pt-online-schema-change --execute --alter "Engine = InnoDB" h=127.0.0.1,D=d1,t=t1,u=root,P=64057 --recursion-method=hosts
..
# MasterSlave:4031 30218 Recursion methods: hosts
# MasterSlave:4041 30218 Connected to D=d1,P=64057,h=127.0.0.1,t=t1,u=root
# MasterSlave:4050 30218 SELECT @@SERVER_ID
# MasterSlave:4052 30218 Working on server ID 1057
# MasterSlave:4085 30218 Looking for slaves on D=d1,P=64057,h=127.0.0.1,t=t1,u=root using methods hosts
# MasterSlave:4092 30218 Finding slaves with _find_slaves_by_hosts
# MasterSlave:4126 30218 DBI::db=HASH(0x3260a08) SHOW SLAVE HOSTS
# MasterSlave:4130 30218 Found some SHOW SLAVE HOSTS info
..
# MasterSlave:4097 30218 Found 1 slaves
# MasterSlave:4074 30218 Recursing from D=d1,P=64057,h=127.0.0.1,t=t1,u=root to D=d1,P=64056,h=,u=root
..
Cannot connect to D=d1,P=64056,h=,u=root
# pt_online_schema_change:8027 30218 0 slaves found
..

mysql57> show slave hosts;
+-----------+------+-------+-----------+--------------------------------------+
| Server_id | Host | Port  | Master_id | Slave_UUID                           |
+-----------+------+-------+-----------+--------------------------------------+
|      1056 |      | 64056 |      1057 | 5ceebb66-c191-11e4-b66a-001a4aa000e2 |
+-----------+------+-------+-----------+--------------------------------------+
1 row in set (0.00 sec)

SHOW SLAVE HOSTSの結果からHostとPortをパースして接続に行く。一見万能そうだが、--report-hostを指定していない場合は空欄になってしまって上手くパースできていない("Cannot connect to D=d1,P=64056,h=,u=root")
あと、MySQL 5.5.23からは--report-portを指定しなかった場合は暗黙のデフォルトとしてmysqldのポートが使われるのだが、それ以前の場合は3306が暗黙のデフォルトとして使われてしまうし、5.5.3より前のバージョンはそもそも--report-hostが設定されていない場合はSHOW SLAVE HOSTSに全く表示されない。

というわけで--report-hostと--report-portが正しく設定されている場合(5.5.23以降はreport-portは未指定でもいい)のみ使えるrecursion-methodで、これらはオンラインで変更できないオプションなので、pt-oscのためだけに変更するのはなんかコレジャナイ感しかしない。

MySQL :: MySQL 5.5 Reference Manual :: 13.7.5.34 SHOW SLAVE HOSTS Syntax


* dsn

というわけで、↑の条件を満たさない(非標準ポートで使っていて、--report-hostや--report-portが全てのmysqldに行き渡っているわけではない)場合に使えるrecursion-methodってこれしか残らないと思うんだけど、ぐぐっても(英語ですら)ほとんど情報がなかった。


mysql57> create table mysql.slave (id int, dsn varchar(255));
Query OK, 0 rows affected (0.67 sec)

mysql57> INSERT INTO mysql.slave VALUES (1, 'h=127.0.0.1,P=64056,u=root');
Query OK, 1 row affected (0.23 sec)

mysql57> SELECT * FROM mysql.slave;
+------+----------------------------+
| id   | dsn                        |
+------+----------------------------+
|    1 | h=127.0.0.1,P=64056,u=root |
+------+----------------------------+
1 row in set (0.12 sec)

ここは下準備。別にmysqlスキーマに作らなくてもいいし、テーブル名も何でもいい。pt-oscのオプションで任意の値を指定できる。
カラムも(マニュアルには色々書いてあるけど)`id`カラムと`dsn`カラムさえあればそれでいい。発行されるクエリーはSELECT dsn FROM .. ORDER BY idだったので、それが結果を返しさえすればOKだ。今のところは。


$ PTDEBUG=1 pt-online-schema-change --execute --alter "Engine = InnoDB" h=127.0.0.1,D=d1,t=t1,u=root,P=64057 --recursion-method="dsn=D=mysql,t=slave"
..
# MasterSlave:4598 30328 DSN table DSN: D=mysql,t=slave
..
# MasterSlave:4619 30328 SELECT dsn FROM `mysql`.`slave` ORDER BY id
# MasterSlave:4624 30328 DSN from DSN table: h=127.0.0.1,P=64056,u=root
..
# pt_online_schema_change:8027 30328 1 slaves found
# pt_online_schema_change:8052 30328 Will check slave lag on all slaves
# pt_online_schema_change:8070 30328 Checking slave replication filters
# MasterSlave:4268 30328 DBI::db=HASH(0x2a07458) SHOW MASTER STATUS
# MasterSlave:4272 30328 binlog_do_db= file=bin.000006 position=234290939 executed_gtid_set=5ceebb66-c191-11e4-b66a-001a4aa000e2:1-13,
# ecb991db-cb86-11e4-b75b-001a4aa000e2:1-613048 binlog_ignore_db=
# MasterSlave:4244 30328 DBI::db=HASH(0x2a07458) SHOW SLAVE STATUS
# MasterSlave:4570 30328 DBI::db=HASH(0x2a07458) SHOW VARIABLES LIKE 'slave_skip_errors'
..

この通り、--recursion-method="dsn=.."で指定したスキーマ, テーブルにクエリーを発行してそこからDSNを拾う。processlistの時と同じく、テーブルのdsnカラムに指定されていない部分はマスターに接続するときに使ったDSNをそのまま流用するらしい。ホスト名とポート番号だけでなくユーザーとパスワードも指定しておいた方がいい(や、rootでどのホストからでもアクセスできるならいいけど)

また、これをやっておくと多少遅延してもいいけど性能の悪いバックアップ用のスレーブのラグに引きずられて、pt-osc自体の進行が遅くなる…とかいうのも防げる。ビバ。

ちなみに接続先のDSNを間違えて、レプリケーションのつながっていないホストに接続してしまうと、

Waiting forever for new table `d1`.`_t1_new` to replicate to myhost...

( ´-`).oO(マスターで_t1_newをCREATE TABLEした後にスレーブで_t1_newが作られてるか確認してスリープしながら無限ループしてるだけ(なので、すさまじく遅延したレプリケーション環境では出うる)んだけど本当にforever待ってしまうという。。

0 件のコメント :

コメントを投稿