TL;DR
- まず間違いなく mysql.gtid_executed が悪さをしている
- 去年隣にいた人 も 6月まで隣にいた人 も 今2つ隣にいる人 もハマった
- ルーク、
CHANGE MASTER TO
する前にRESET MASTER
を忘れるな。RESET SLAVE ALL
だけじゃダメだ、RESET MASTER
もだ。そしてSET GLOBAL gtid_purged = '..'
しろ
GTIDを有効にしてレプリケーションを組んでいる(
MASTER_AUTO_POSITION=1
)場合、実行済みのトランザクションのGTIDは gtid_executed に記録される。
そしてI/Oスレッドは 自分のgtid_executedに含まれていない イベントがあれば寄越せ、というように接続時にマスターに要求するし、仮に自分のgtid_executedに含まれているイベントが寄越されてもSQLスレッドが同じGTIDのイベントの二重適用を防ぐ。
これでレプリケーションのポジションはズレない。ズレるはずがない。
gtid_executedが間違っていなければ
じゃあどこでgtid_executedが間違うのか。
- gtid_executedはそもそもサーバー変数で、オンメモリーだ。取り敢えずのところ、mysqldが停止しなければgtid_executedは間違わない(はず。間違うならそれはバグだ)
- mysqldが停止した場合、サーバー変数のgtid_executedは当然値が失われる。その場合、バイナリーログ(openしてれば)とmysql.gtid_executedから復元する
- mysql.gtid_executedはバイナリーログをopenしている場合はバイナリーログのスイッチ時とmysqldのシャットダウン時、openしていない場合はコミットの都度書き込む。マスターは確実にバイナリーログをopenしているので前者の動きになる
- ところで、ここに稼働中のマスターサーバーから取ったXtraBackupがあるじゃろ?
- トランザクションで保護するからmysql.gtid_executedテーブルはXtraBackup開始時の値が保管されるじゃろ?
- XtraBackupはバイナリーログは取らないじゃろ? (あればbinlogに記録されている分からgtid_executedをリカバってくれる)
- リストアして
CHANGER MASTER TO .. MASTER_AUTO_POSITION= 1
するとサクッとズレる - _| ̄|○
リストアしてから
CHANGE MASTER TO ..
の前に、 RESET MASTER
で gtid_executedの中身を吹っ飛ばし、 SET GLOBAL gtid_purged = '..'
で設定するのが正しいと思う。
MySQL 5.7.18とそれ以前のmysqldumpでも同じことが起きる(
--all-database
でmysql.gtid_executedをダンプしてしまう)し、事実 去年隣にいた人 はmysqldumpで踏んでた。これは最近リリースされたMySQL 5.7.19のmysqldumpでは直っているそうだけれども。
まあ何にせよ注意。。