Slide 1

Slide 1 text

いまさらMySQLの非同期レプリケーションでの HAの難しさについて考える いやホント難しすぎませんか 2025/07/10 yoku0825

Slide 2

Slide 2 text

\こんにちは/ yoku0825@とある企業のDBAだったもの オラクれない ‐ ポスグれない ‐ マイエスキューエる ‐ 生息域 Twitterだったもの: @yoku0825 ‐ Blog: 日々の覚書 ‐ 日本MySQLユーザ会副代表 ‐ MySQL Casual ‐ 1/19

Slide 3

Slide 3 text

おことわり これは俺が今の会社に入社する前に温めていたネタなので、発表は個人のものであ り所属する組織には何の関係もありません 2/19

Slide 4

Slide 4 text

ここまでのあらすじ MySQLのレプリケーションは非同期(準同期レプリケーションを含む, グループレ プリケーションは除外する) ソースサーバのストレージエンジンに書く(= InnoDBログにwrite/fsyncする)のと ほぼ同時にバイナリログに書く(= write/fsyncする) バイナリログをレプリカサーバに転送 レプリカサーバは転送されたバイナリログイベントをリプレイすることでストレー ジエンジンを同期させる 3/19

Slide 5

Slide 5 text

ここまでのあらすじ MySQLレプリケーションあれやこれや - Speaker Deck その行がマスターにINSERTされてからスレーブでSELECTされるまで - Speaker Deck MySQL徹底入門 第5版 MySQL 8.4 LTS対応|翔泳社の本 4/19

Slide 6

Slide 6 text

HAを考えるときの悩みポイント MySQLのレプリケーションは非同期(準同期レプリケーションを含む, グループレ プリケーションは除外する) ソースサーバのストレージエンジンに書く(= InnoDBログにwrite/fsyncする)のと ほぼ同時にバイナリログに書く(= write/fsyncする) 書き出されたバイナリログをレプリカサーバに転送 レプリカサーバは転送されたバイナリログイベントをリプレイすることでストレー ジエンジンを同期させる 5/19

Slide 7

Slide 7 text

HAを考えるときの悩みポイント MySQLのレプリケーションは 非同期 (準同期レプリケーションを含む, グループレ プリケーションは除外する) ソースサーバのストレージエンジンに書く(= InnoDBログにwrite/fsyncする)のと ほぼ同時に バイナリログに書く(= write/fsyncする) 書き出されたバイナリログをレプリカサーバに 転送 レプリカサーバは転送されたバイナリログイベントを リプレイ することでスト レージエンジンを同期させる 6/19

Slide 8

Slide 8 text

ストレージエンジンとバイナリログ ソースサーバーの一貫性はどうやら保てるらしい InnoDBログにfsyncしてからバイナリログにfsync(MySQL 8.0からInnoDBログライタース レッドが爆誕したのでwriteの順番は保証されない)してコミットが完了する 2PC between Binlog and InnoDB ‐ 分散でない(= 1プロセスの中の)2 Phase Commitだからクラッシュリカバリで辻褄を合わせら れるらしい ‐ バイナリログのfsync以降にCOMMIT OKを返す前にクラッシュしたら「書けてな いように見えるものが残る」のはそうなんだけれど それを言ったらクラッシュしてなくてもCOMMIT OKを返す前にTCP RSTとか走ったらそれは コミットできたと言えるのかどうかとか難しい話になりそう ‐ 7/19

Slide 9

Slide 9 text

ストレージエンジンとバイナリログ 2PC between Binlog and InnoDB 8/19

Slide 10

Slide 10 text

ストレージエンジンとバイナリログ バイナリログはwriteされた時点からレプリカ転送のターゲットになる fsyncがまだでソースが電源障害で消えてロールバック対象になったとしても転送済みのバイナ リログイベントは1台のクラッシュリカバリではどうにもならない 系全体として取りえる状態が爆増する ‐ 9/19

Slide 11

Slide 11 text

クラッシュリカバリで消えないようにするのが準同期レプリケーション 準同期レプリケーションが効いている限り「ソースは必ず最後にACKを返したレプ リカと同じ(コミット済)かそれ以下のバイナリログしか持っていない(ロールバッ クされる)」ことが保証できるので「ソースが落ちたら必ずフェイルオーバー」が 定石 それでも複数台のレプリカの中で一番バイナリログを持っているのは誰かを判定す る必要はある(けどこれはGTIDを使わなくても全然楽) よくある勘違いだけれど非同期レプリケーションと準同期レプリケーションを混ぜた場合、 「一番バイナリログを持っているもの = 準同期レプリカ」には ならない ‐ あくまで「ACKを返す能力があるかどうか」だけの違いなので吸い上げのタイミングは影響を 受けない ‐ 10/19

Slide 12

Slide 12 text

不本意なフェイルオーバー 綺麗にプロセスが落ちたり電源が落ちたりしてくれれば全然良い ヘルスチェックには死んだふりをして、フェイルオーバープロセスがトリガーされ た後に蘇ってくるのが一番困る ex. 昔のInnoDBはDROP TABLEで刺さりがち → 1分くらい刺さってフェイルオーバー発動 → DROP TABLE処理が完遂してまた処理を再開する 😱 ‐ ex. ハードウェアの間欠障害, メモリ不足によるスラッシング, Noisy Nighbor.. Split Brain! ‐ 11/19

Slide 13

Slide 13 text

強気な準同期レプリケーションでのフェンシング ソースが健全であれば切り替えの時に使う SET GLOBAL read_only = ON はフェイル オーバー中にはフェンシングできないことがある ソースが「刺さった」状態ならこのSQLはだいたい噛まれる ‐ 他のクエリも全部噛んでOKパケットを投げないことなんて保証できない 「噛んだ後にしばらくして復帰してくる」悲劇 ‐ ソースが一切のSQLを受け付けなくてもソースの更新を妨げる方法が必要 → 強気な準同期レプリケーション ‐ 12/19

Slide 14

Slide 14 text

強気な準同期レプリケーションでのフェンシング rpl_semi_sync_source_wait_for_replica_count=1 , rpl_semi_sync_source_wait_no_replica=ON, rpl_semi_sync_source_timeout=4294967295 1以上の任意の台数の準同期レプリカ 強い心で非同期レプリカは作らせない 準同期レプリカが全部落ちると系は書き込み不可能になる タイムアウトの値は譲れない 準同期レプリケーションが非同期レプリケーションにフォールバックしちゃうと全ての前提が 崩れる ‐ 13/19

Slide 15

Slide 15 text

強気な準同期レプリケーションでのフェンシング ソースが刺さったように見えたら? 全ての準同期レプリカで iptables でソースのIPアドレスをブロックする ソースにログインできなくてもソースでトランザクションがコミットされるのを防げる ‐ ソースの電源を落とす。落としきるまでは絶対に書き込ませ(= COMMIT OKを返させ)ない。 電源が落ちるまでに復活したとして、 iptables がかかりきる前にSemisyncで渡った(=COMMIT OKを返した)部 分は必ず誰かが持っている iptables がかかりきった後のCOMMITは絶対成功しない(= COMMIT OKが返らない) COMMIT OKが返らなくてもバイナリログに書いている以上、 iptables をかけない(つもりでいる)非同期レプリカ は吸い上げてしまう可能性があるので作らせない ‐ 電源が確実に落ちたら iptables の解除&レプリカの昇格処理 ‐ 14/19

Slide 16

Slide 16 text

バイナリログイベントのコンバージェンス ソースを確実に落としきれればあとは「一番バイナリログイベントを持っているレ プリカ」を次のソースに昇格させればいい GTIDだろうと何だろうと、もとのソースではバイナリログ上に直線的に記録されているので、 SHOW REPLICA STATUS の Source_Log_File と Read_Source_Log_Pos が最大になっているレプリカ が一番バイナリログを持っているレプリカ レプリカ同士で比較する時は Relay_Source_Log_File と Exec_Source_Log_Pos ではない。リレーログに入っている なら待てば Source_Log_File = Relay_Source_Log_File && Source_Log_File = Exec_Source_Log_Pos になる 変にSQLスレッド基準で比較すると、「せっかくリレーログまで吸い込んでるのにむざむざそれを捨てる」ことに なる ‐ 15/19

Slide 17

Slide 17 text

バイナリログイベントのコンバージェンス 全部準同期でも(地理的な問題で)フェイルオーバー優先度が決まっていたりする 2段階フェイルオーバー 「一番バイナリログイベントを持っているレプリカ」をソースとしてレプリケーション構成を 組む ‐ しばらく待てば再構成後のすべてのレプリカは同じ gtid_executed に収束する 全マシンがHealthyな状態で優先順位が高いサーバにスイッチオーバーすればいい ‐ 16/19

Slide 18

Slide 18 text

バイナリログイベントのコンバージェンス 個人的には(STPっぽく)コンバージェンスと呼んでいる 準同期レプリケーションはスローコンバージェンス ‐ グループレプリケーションはファストコンバージェンス ‐ というか準同期レプリカ1台だとSPoFになって2台以上…となると3台になるのでグ ループレプリケーションで良くない? 性能特性が違うので、自分で使うならまだしも人に使えというのは微妙なライン ‐ 17/19

Slide 19

Slide 19 text

最近見かけたバグレポート MySQL Bugs: #118412: DML succeeds on Semi-sync without Replicas if Source is stopped 18/19

Slide 20

Slide 20 text

Any Question and/or Suggestion? 19/19