スレーブ側で--replicate-do-や--replicate-ignore-などのルールを使ってフィルタリングをすると、GTIDに欠番ができて、連番が連続しなくなるため、SHOW SLAVE STATUSの出力が大変なことになってしまう。GTIDを用いるときは、フィルタリングしないのほうが無難である。
replicate-do-db
などでスレーブでフィルタしていると GTID に欠番が生じてスレーブの Executed_Gtid_Set
がすごいことになる。ということだと思うのですが、GTID はトランザクション単位で採番されるものの replicate-do-db
とかはステートメント単位とかだと思うので(1つのトランザクションの中にフィルタされる更新とされない更新が混ざることがある)、直感的にはトランザクションの一部がフィルタされたときはマスターとスレーブでトランザクションの内容に差異が生じて、全部フィルタされたときも GTID が欠番にはならずに空のトランザクションになりそうな気がしたので、試してみました。
試したバージョンは次の通り。
mysqld --version /usr/sbin/mysqld Ver 8.0.11 for Linux on x86_64 (MySQL Community Server - GPL)
docker-compose.yml
version: '3.4' services: sv01: image: mysql:8 environment: MYSQL_ALLOW_EMPTY_PASSWORD: 1 MYSQL_DATABASE: test networks: mysql: ipv4_address: 192.168.88.11 command: - --default_authentication_plugin=mysql_native_password - --skip-name-resolve - --character-set-server=utf8 - --innodb-file-per-table - --log-bin=mysql-bin - --sync-binlog=1 - --relay-log=relay-bin - --log-slave-updates - --skip-slave-start - --binlog-format=row - --replicate-do-db=test - --slave-exec-mode=IDEMPOTENT - --master-info-repository=TABLE - --relay-log-info-repository=TABLE - --relay-log-recovery=ON - --gtid-mode=ON - --enforce-gtid-consistency - --server-id=1 sv02: image: mysql:8 environment: MYSQL_ALLOW_EMPTY_PASSWORD: 1 MYSQL_DATABASE: test networks: mysql: ipv4_address: 192.168.88.12 command: - --default_authentication_plugin=mysql_native_password - --skip-name-resolve - --character-set-server=utf8 - --innodb-file-per-table - --log-bin=mysql-bin - --sync-binlog=1 - --relay-log=relay-bin - --log-slave-updates - --skip-slave-start - --binlog-format=row - --replicate-do-db=test - --slave-exec-mode=IDEMPOTENT - --master-info-repository=TABLE - --relay-log-info-repository=TABLE - --relay-log-recovery=ON - --gtid-mode=ON - --enforce-gtid-consistency - --server-id=2 networks: mysql: driver: bridge ipam: driver: default config: - subnet: 192.168.88.0/24
docker-compose
で環境を立ち上げる。
docker-compose up docker-compose exec sv01 bash docker-compose exec sv02 bash
レプリケーション用のユーザーを作成。
# [sv01/sv02] mysql mysql -v <<'SQL' CREATE USER 'repl'@'%' IDENTIFIED BY 'pass'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; SQL
バイナリログがわかりやすくなるように reset master
しとく。
# [sv01/sv02] mysql mysql -v <<'SQL' reset master; SQL
レプリケーションを開始。
# [sv02] mysql mysql -v <<'SQL' change master to MASTER_HOST = '192.168.88.11', MASTER_USER = 'repl', MASTER_PASSWORD = 'pass', MASTER_AUTO_POSITION = 1; start slave; SQL
--replicate-do-db=test
により test
データベース以外はスレーブでフィルタされるようになっているので、適当に別のデータベースを作るなどしてマスターを更新します。
/* [sv01] */ use test create table t (id int not null primary key, no int not null); insert into t values (1, 111); /* [sv01/sv02] */ select * from t; /* [sv01] */ create database hoge; use hoge create table h (id int not null primary key, no int not null); insert into h values (1, 111); /* [sv01] */ use test insert into t values (2, 222);
GTID を見てみます。
/* [sv01/sv02] */
show master status \G
show slave status \G
見た感じ欠番が生じてる雰囲気はありません。次のように mysqlbinlog
を見比べてみても、
mysqlbinlog mysql-bin.000001 --include-gtids=6930f785-7376-11e8-9b24-0242c0a8580b:5 --base64-output=DECODE-ROWS -v
sv01
BEGIN /*!*/; # at 1197 #180619 5:22:14 server id 1 end_log_pos 1245 CRC32 0xb5b056b1 Table_map: `hoge`.`h` mapped to number 107 # at 1245 #180619 5:22:14 server id 1 end_log_pos 1289 CRC32 0xe5c002ce Write_rows: table id 107 flags: STMT_END_F ### INSERT INTO `hoge`.`h` ### SET ### @1=1 ### @2=111 # at 1289 #180619 5:22:14 server id 1 end_log_pos 1320 CRC32 0xf366fedf Xid = 122 COMMIT/*!*/;
sv02
BEGIN /*!*/; # at 1265 #180619 5:22:14 server id 1 end_log_pos 1332 CRC32 0x7b096e01 Query thread_id=17 exec_time=0 error_code=0 SET TIMESTAMP=1529385734/*!*/; COMMIT
スレーブでフィルタされた処理は空のトランザクションとなって記録されているようです。
ので replicate-do-db
などを用いてフィルタしてもスレーブで GTID に欠番がでることはなさそうです。
さいごに
参考にした記事はだいぶ古く(3年半ぐらい前)、バージョンも 5.6 とかなので、今回試した 8.0.11 だとその辺の事情も変わってるのかもしれません。
現代は GTID レプリケーションと replicate-do-db
などを併用しても問題ない、と思います。