MySQL道普請便り

第279回MySQL Group ReplicationのDistributed Recoveryについて

MySQL Group Replicationでは、新規メンバーの参加や障害からの復帰の際に、グループから離脱していた期間に発生したトランザクションの同期が必要になります。この同期処理を担うのがDistributed Recoveryです。

Group Replicationの基礎知識についての過去の記事も参考にしてください。

動作はMySQL 9.7.0の3ノード構成(node1:3306、node2:3307、node3:3308)で行っています。

Distributed Recoveryとは

グループへの参加・復帰時、メンバーはまずRECOVERING状態になり、グループ内の他のメンバー(ドナー)からデータを受け取って状態を合わせます。この一連の仕組みをDistributed Recoveryと呼びます。

Distributed Recoveryが発生するタイミングは主に以下のケースです。

  • 新規ノードをグループに追加するとき
  • 障害・ネットワーク分断から復帰するとき
  • メンテナンスのために一時的にグループを離脱したノードを再参加させるとき

いずれのケースでも、参加するメンバー(ジョイナー)はRECOVERING状態のまま自動的に同期を開始し、同期が完了するとONLINEに遷移します。

RECOVERING状態のメンバーはグループのクォーラム(過半数の合意)にはカウントされますが、グループ参加時にsuper_read_only=ONが設定されるため、クライアントからの書き込みは受け付けられません。読み取りは可能ですが、データが途中までしか適用されていないため、古い値が返ることがあります。回復中のメンバーが長時間RECOVERING状態にとどまる場合、システム全体への影響を考慮して適切な対処が必要です。

Distributed Recoveryの全体フロー

メンバーがSTART GROUP_REPLICATIONを実行してからONLINEになるまでの流れは以下の通りです。

START GROUP_REPLICATION
  ↓
RECOVERING 状態へ遷移
  ↓
group_replication_applier relay log の確認・未適用トランザクション適用(再参加時のみ)
  ↓
回復方式の決定(Clone / Binlog ベース)
  ↓
ドナー選択
  ↓
State Transfer(データ受信)※State Transfer 中の新着トランザクションはバッファリング
  ↓
バッファリングされたトランザクションの適用
  ↓
ONLINE 状態へ遷移

回復に失敗した場合、メンバーはグループを自動的に離脱します。

フローの先頭ステップで、ジョイナーは自身のgroup_replication_applierチャンネルのrelay logを確認します。再参加の場合、グループを離脱する前にグループから受け取っていた未適用トランザクションがrelay logに残っている可能性があり、その場合はドナーへの接続前にこれらをまず適用します。

以下は実際に3ノード構成(node1:3306、node2:3307、node3:3308)のクラスタで、node3が離脱中に1件のトランザクションが発生した状態で再参加した際のエラーログです。

[node3] 2026-09-05T02:45:58.996335Z Plugin group_replication reported:
  'Distributed recovery will transfer data using: Incremental recovery from a group donor'
[node3] 2026-09-05T02:45:58.996675Z Plugin group_replication reported:
  'Group membership changed to db-server:3306, db-server:3307, db-server:3308 on view 17885763218885184:5.'
[node3] 2026-09-05T02:45:59.021448Z 'CHANGE REPLICATION SOURCE TO FOR CHANNEL 'group_replication_recovery' executed'.
  Previous state source_host='<NULL>', source_port= 0
  New state source_host='db-server', source_port= 3307
[node3] 2026-09-05T02:45:59.167514Z Replica receiver thread for channel 'group_replication_recovery':
  connected to source 'repl@db-server:3307' with server_uuid=255e1238-..., server_id=2.
  Starting GTID-based replication.
[node3] 2026-09-05T02:45:59.170128Z Replica SQL thread stopped because it reached
  UNTIL SQL_AFTER_GTIDS aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:1-357:1000001-1000123
[node3] 2026-09-05T02:45:59.175239Z 'CHANGE REPLICATION SOURCE TO FOR CHANNEL 'group_replication_recovery' executed'.
  Previous state source_host='db-server', source_port= 3307
  New state source_host='<NULL>', source_port= 0
[node3] 2026-09-05T02:45:59.179735Z Plugin group_replication reported:
  'This server was declared online within the replication group.'
[node3] 2026-09-05T02:46:00.000765Z Plugin group_replication reported:
  'Plugin 'group_replication' has been started.'

UNTIL SQL_AFTER_GTIDSに記録されたGTID範囲が回復対象のトランザクション範囲です。このGTIDにジョイナーが追いつくとレプリケーションSQLスレッドが自動停止し、ドナー接続が解除されてONLINEに遷移します。

回復方式の選択

Distributed RecoveryにはBinlogベースとCloneベースの2つの回復方式があり、START GROUP_REPLICATION後に自動的に選択されます。

Cloneベース
欠落GTID数がgroup_replication_clone_thresholdを超える場合、またはbinlogがpurge済みでBinlogベースが使えない場合に選択されます。いずれの場合もClone対応ドナーの存在が前提です。
Binlog ベース
それ以外の場合(差分が閾値以内かつドナーのbinlogが残っている)に選択されます。Clone Pluginがインストールされていない場合も、この方式のみが使われます。

Binlogベースの回復

group_replication_recoveryチャンネルを通じてドナーから欠落トランザクションを受け取り、順次適用します。データファイルの転送もジョイナーの再起動も不要なため、差分が小さければ短時間で完了します。

State Transferの完了後、その間にグループで発生したトランザクションをバッファから適用し、すべて追いついた時点でONLINEに遷移します。

前提条件として、ドナー側に欠落トランザクションをカバーするbinlogが残っている必要があります。binlog_expire_logs_secondsの設定が短すぎるとbinlogが先に削除されてしまい、Cloneベースへのフォールバックが発生します。

Cloneベースの回復

MySQL Clone Pluginを使ってドナーのデータを新規メンバーに丸ごとコピーします。具体的には以下の順序で実行されます。

  1. ドナーからデータファイルをCloneで転送
  2. ジョイナーが自動的に再起動
  3. 再起動後、Clone中に発生した差分トランザクションをBinlogベースで補完
  4. ONLINEに遷移

この方式を有効にするには、Clone Pluginのインストールが必須です。ドナー・ジョイナー双方にインストールされていない場合、group_replication_clone_thresholdを設定してもCloneは実行されません。また、Clone中はジョイナーのデータファイルがドナーのスナップショットで完全に上書きされるため、ジョイナー側に既存データがある場合は消去される点に注意してください。

Clone Pluginをインストール(ドナー・ジョイナー双方で実施)
INSTALL PLUGIN clone SONAME 'mysql_clone.so';

Clone Pluginの基本的な使い方は第127回「CLONEプラグインを導入しよう」でも紹介しています。

Cloneを使うにあたって、以下の2点も必要です。

同一OS⁠・同一リリースシリーズ
ドナーとジョイナーは同じOSおよび同じMySQLリリースシリーズで動作している必要があります。たとえばMySQL 8.0と8.4は別シリーズのためCloneは使えません。
BACKUP_ADMIN権限
Cloneではレプリケーションユーザーがドナー側のCloneユーザーとして機能します。Cloneをサポートするすべてのメンバーで、分散回復用のレプリケーションユーザーにBACKUP_ADMIN権限を付与してください。

group_replication_clone_thresholdのデフォルト値はGNO_END実質的に無効)です。つまり、デフォルト設定では閾値超過によるCloneの自動選択は発生しません。binlogがpurge済みの場合のみ、フォールバックとしてCloneが選ばれます。

閾値を明示的に設定することで、大きな差分がある場合に積極的にCloneを使うことができます。

1000トランザクション以上の差分があればCloneを選択する例
SET @@GLOBAL.group_replication_clone_threshold = 1000;

このパラメータはGroup Replication実行中でも動的に変更可能ですが、現在進行中の回復には影響せず、次回以降の回復から反映されます。

閾値を低くしすぎると、Clone実行中にグループ内のトランザクション数が閾値を超え続け、再起動後に再びCloneが起動するというループに陥るリスクがあります。閾値はClone操作にかかる時間内にグループで発生すると想定されるトランザクション数より十分大きい値に設定してください。

また、Cloneベースを使う場合はジョイナーの自動再起動が発生します。サーバー設定(my.cnf)としてgroup_replication_start_on_boot=ONが設定されていると、再起動後に自動的にGroup Replicationが再開し、回復の後半フェーズ(差分のBinlog補完)に進みます。この設定がない場合は再起動後に手動でSTART GROUP_REPLICATIONを実行する必要があります。

ドナー選択の仕組み

ジョイナーがどのノードからデータを受け取るかは、ソースコード(recovery_state_transfer.cc)に実装されたドナー選択ロジックで決まります。

選択基準

以下の条件をすべて満たすメンバーがドナー候補になります。

  1. ONLINE 状態であること
  2. 自分自身でないこと
  3. バージョン互換性があること
    • Binlogベース:ドナーのバージョンがジョイナー以下、または同じLTSバージョン
    • Cloneベース:同じOSおよび同じMySQLリリースシリーズ

候補が複数いる場合はランダムに接続を試みます。以下の例では、グループ起動時にnode2が参加した時点では自身を除くONLINEメンバーはnode1のみであったため、node1が選ばれます。node3が参加した時点ではnode1、node2が候補でしたが、ランダム選択の結果node1が選ばれました。

# node2 はドナーとして node1 (port 3306) を選択
[node2] 2026-09-05T02:45:26.012277Z 'CHANGE REPLICATION SOURCE TO FOR CHANNEL 'group_replication_recovery' executed'.
  Previous state source_host='<NULL>', source_port= 0
  New state source_host='db-server', source_port= 3306

# node3 はドナーとして node1 (port 3306) を選択
[node3] 2026-09-05T02:45:31.015463Z 'CHANGE REPLICATION SOURCE TO FOR CHANNEL 'group_replication_recovery' executed'.
  Previous state source_host='<NULL>', source_port= 0
  New state source_host='db-server', source_port= 3306

再試行の流れ

ドナーへの接続が失敗した場合、次の候補に切り替えながら再試行します。候補が尽きた場合はgroup_replication_recovery_reconnect_interval(デフォルト60秒)の間待機してからドナーリストを再構築し、再度試みます。

ドナー接続試行
  ↓ 失敗
次のドナー候補に切り替え
  ↓ 候補が尽きた場合
  reconnect_interval秒待機 → リスト再構築 → 再試行
  ↓ retry_countが上限(デフォルト:10)に達した場合
回復失敗 → グループを自動離脱

group_replication_recovery_retry_countはドナーへの接続の「総試行回数」で、ドナーを切り替えるたびにカウントアップされます。デフォルトの10は「10種類のドナーへの接続試行が上限」であり、1つのドナーへのリトライ回数ではない点に注意が必要です。

候補リストの再構築時には、グループ内の最新のメンバー状態を元にリストを作り直します。そのため、最初の試行でドナーが全滅した後に他のノードがONLINEになった場合、reconnect_interval後の再試行で新たにドナーとして選ばれる可能性があります。

回復失敗時

State Transferの試行がgroup_replication_recovery_retry_countの上限に達すると、メンバーは自動的にグループを離脱します。以下はgroup_replication_recovery_retry_count = 2の状態で誤った認証情報を設定し、node3を参加させた際の実際のエラーログです。

# ドナー #1(3307)→ ドナー #2(3306)と順に試みるが、いずれも認証失敗
[node3] 2026-09-07T12:41:49.497846Z [ERROR] Replica I/O for channel 'group_replication_recovery':
  Error connecting to source 'nonexistent_user@db-server:3307'. Error_code: MY-001045
[node3] 2026-09-07T12:41:49.498147Z [ERROR] Plugin group_replication reported:
  'There was an error when connecting to the donor server. ...'
  (ドナー #2(3306)でも同様の失敗)

# 試行回数の上限に達し、回復を中止してグループを自動離脱
[node3] 2026-09-07T12:41:49.516840Z [ERROR] Plugin group_replication reported:
  'Maximum number of retries when trying to connect to a donor reached.
  Aborting group replication incremental recovery.'
[node3] 2026-09-07T12:41:49.516850Z [ERROR] Plugin group_replication reported:
  'Fatal error during the incremental recovery process of Group Replication.
  The server will leave the group.'
[node3] 2026-09-07T12:41:52.553170Z Plugin group_replication reported:
  'Group membership changed: This member has left the group.'

グループを離脱した後、メンバーはERROR状態になります。この状態からの復帰にはSTART GROUP_REPLICATIONの手動実行が必要です。根本的な原因(認証情報の誤り/binlogのpurge済み/ドナーの不在など)を解消してから再参加させる必要があります。

まとめ

Distributed Recoveryは自動で完結しますが、成否は事前の設定に大きく左右されます。

  • binlogがpurge済みでClone Pluginも未インストールの場合、どちらの回復方式も使えず回復が失敗します。この組み合わせが最も避けるべき状態です
  • Cloneベースではジョイナーが自動再起動します。group_replication_start_on_boot=ONを設定しておかないと、再起動後に差分補完フェーズへ自動で進まず手動介入が必要になります
  • 回復に失敗したメンバーは自動的にグループを離脱してERROR状態になります。原因を解消してからSTART GROUP_REPLICATIONを手動実行してください

参考情報

おすすめ記事

記事・ニュース一覧