同期/準同期/非同期レプリケーションとフェイルオーバー
コミット確認をいつ返すかで、データ損失と書き込み遅延のトレードオフが決まります。同期・準同期・非同期の境界と、フェイルオーバー時の損失・分岐の起き方を原理から押さえられます。
- 1.違いは「プライマリがクライアントへコミット成功を返す瞬間に、変更がどこまで耐久化されているか」の一点。非同期はローカル書き込み時点、準同期はレプリカが受領(または書き込み)した時点、同期はレプリカが永続化した時点で返す。
- 2.この瞬間の取り方が RPO/RTO を決める。同期はRPO=0に近づくがプライマリの応答が遠いレプリカの待ちに律速され、非同期は速いがフェイルオーバーで未送出ぶんが消える。準同期は「過半数のうち1台」など耐久化条件を緩めて両者の中間を取る。
- 3.フェイルオーバーの危険は2つ。昇格レプリカが追いつけていないことによるデータ損失(lost updates)と、旧プライマリが生き返って二重に書くスプリットブレイン。後者はフェンシングと過半数クォーラムで封じる。
違いを生むのは「コミット確認を返す瞬間」だけ
同期・準同期・非同期レプリケーションは、転送する内容(物理か論理か)でも、レプリカが何台あるかでもなく、プライマリがクライアントに「コミット成功」を返す前に、変更がどこまで耐久化されているかという一点だけで分かれます。
WAL(先行書き込みログ)を前提にコミットの内部手順を分解すると、起きることは常に同じ順序です。
コミット時のプライマリの動き:
1. WAL レコードをローカルのログバッファ→ディスクへ flush/fsync
2. WAL レコードをレプリカへ送信
3. レプリカが受領/ディスクへ書き込み/適用
4. クライアントへ「コミット成功」を返す ← この行を「どこまで進んだら」実行するか
非同期は手順1の直後に4へ進みます。同期は手順3(レプリカの永続化)を待ってから4へ進みます。準同期はその中間で、「レプリカが受領した」または「レプリカがディスクに書いた(だが適用はまだ)」時点で4へ進みます。待つ地点をどこに置くか——本質はこれだけで、性能・耐久性・可用性のすべてがここから導かれます。
クライアントにコミット成功を返すとは「この変更はもう失わない」という契約を結ぶことです。だから損失が起きるかどうかは、契約を結ぶ瞬間(手順4)に変更がどこに何部存在するかで決まります。プライマリのディスク1部しかない状態で契約を結べば、そのディスクと運命を共にします。これが非同期の損失の正体です。
三方式の境界とRPO/RTO
可用性設計の評価軸は RPO(目標復旧時点=最大どれだけのデータ損失を許すか) と RTO(目標復旧時間=どれだけ早く復旧するか) です。レプリケーション方式が直接効くのは主にRPOで、RTOは昇格の自動化や検知速度の問題です。
| 観点 | 非同期 (async) | 準同期 (semi-sync) | 同期 (sync) |
|---|---|---|---|
| 成功を返す条件 | プライマリにflushした時点 | レプリカが受領/書込みした時点 | レプリカが永続化した時点 |
| コミット遅延 | 最小(レプリカに無依存) | RTT 1往復ぶん | RTT+レプリカのfsync待ち |
| 障害時のRPO | 未送出ぶんが損失(>0) | ほぼ0(受領済みは残る) | 0 に最も近い |
| プライマリの足を引っ張るか | 引っ張らない | 1台の応答に律速 | 全(指定)レプリカに律速 |
| レプリカ障害時の挙動 | 影響なし | 降格して継続 or 待機 | 書き込みが詰まりうる |
ここで決定的に重要なのは、同期レプリケーションではプライマリのコミット遅延が、最も遅いレプリカのネットワーク往復時間(RTT)とfsync時間に直接律速される点です。地理的に離れたレプリカ(例:別リージョン)を同期にすると、1コミットごとに往復遅延が乗り、スループットが激減します。同期が「1件も失えない」決済などに限定して使われるのはこのためです。
準同期の典型は「レプリカがWALを受領した(メモリに入れた)時点で成功を返す」設定です。これは速いですが、受領後・ディスク書き込み前にレプリカが落ちると、その変更はどこにも永続化されていない可能性があります。準同期にも「受領で良し」と「ディスク書き込みまで待つ」の段階があり、後者ほど安全だが遅い。どこで線を引いたかを把握せずに「準同期だから安全」と思い込むのが事故のもとです。
準同期がタイムアウトで非同期に化ける問題
準同期は通常「指定台数のレプリカから確認が来るまで待つ」動作ですが、レプリカが落ちたり遅延したりしたときいつまでも待つわけにはいかないので、多くの実装はタイムアウト後に非同期へフォールバックします。
これは可用性を守る合理的な挙動ですが、副作用として**「準同期のつもりがその瞬間だけ非同期だった」窓が生まれます。タイムアウト直後にプライマリが落ちれば、確認を待たずに返したコミットが失われます。「常に準同期である」ことを保証したいなら、確認が取れないコミットはブロックする**(可用性より耐久性を優先する)設定を選ぶ必要があり、これは可用性とのトレードオフそのものです。
フェイルオーバーで何が壊れるか
フェイルオーバーは、プライマリ障害時にレプリカの1台を新プライマリへ**昇格(promote)**させて運転を続ける操作です。ここで起きる事故は原理的に2種類しかありません。
1. データ損失(昇格レプリカが追いついていない)
非同期・準同期では、昇格するレプリカが旧プライマリの最新位置(LSN)まで受け取れていない可能性があります。昇格した瞬間、まだ届いていなかった変更は永久に失われます。クライアントには成功を返していた変更でも、非同期なら消えます。これがRPO > 0の具体的な姿です。
損失を最小化する実務上の定石は、複数あるレプリカのうち最も進んでいる(LSNが最大の)ものを昇格させることです。だが「最も進んでいる」ことと「旧プライマリに完全に追いついている」ことは別なので、非同期である限りゼロ損失は保証できません。
2. 分岐(スプリットブレイン)
より厄介なのは分岐です。旧プライマリが実は生きていた(ネットワーク分断で見えなかっただけ)のに新プライマリを立てると、2台が同時に自分こそプライマリだと思い込み、それぞれ別の書き込みを受け付けます。両者のWALは同じLSNから別々の歴史を刻み、後で統合不能な不整合になります。
分岐(スプリットブレイン)の発生:
T0 P(旧プライマリ) ── ネットワーク分断 ──> 監視からは死んだように見える
T1 R を新プライマリ P' に昇格 (だが P はクライアントAをまだ処理中)
T2 P : LSN 100 で x=1 を書く(クライアントA)
P' : LSN 100 で x=2 を書く(クライアントB)
→ 同じ LSN 100 に互いに異なる変更。どちらが正か判定不能
分岐を防ぐ鉄則は「新プライマリを立てる前に、旧プライマリが二度と書き込めないことを保証する」ことです。これを**フェンシング(fencing)/STONITH(Shoot The Other Node In The Head)**と呼びます。具体的には、旧プライマリの電源・ネットワークを物理的に遮断するか、共有リソースのアクセス権を剥奪します。フェンシングなしの自動フェイルオーバーは、分断のたびに分岐を生む時限爆弾です。
なぜ過半数(クォーラム)が分岐を封じるのか
分岐の根本原因は「お互いを死んだと誤認した2つのグループが、それぞれ独立にプライマリを選べてしまう」ことです。これを構造的に封じるのが過半数クォーラムです。
ノードが奇数台あるとき、過半数(majority)を同時に2グループが確保することは数学的に不可能です(2つの過半数は必ず1台以上で重なる)。そこで「過半数の支持を得たノードだけがプライマリになれる/書き込める」と決めれば、分断が起きてもプライマリになれるグループは多くても1つに限られます。これが合意アルゴリズム Paxos/Raftやクォーラム整合性が高可用構成の土台に使われる理由です。少数派側に取り残されたノードは自ら書き込みを止める(リードオンリーに落ちる)ことで、分岐を未然に防ぎます。
「過半数のレプリカが永続化するまで成功を返さない」同期方式(クォーラムコミット)にすると、コミットは必ず過半数に存在します。フェイルオーバーで新プライマリは過半数から選ばれ、その過半数は元のコミットを含む過半数と必ず重なる——よって確認済みコミットは新プライマリにも必ず存在し、RPO=0が成立します。同期の耐久性と過半数の分岐防止を、ひとつの仕組みで両立させるのがRaftなどのコンセンサスベースHAの肝です。
レプリカラグと「成功」の意味の差
非同期ではレプリカラグ(複製遅延)が常に存在し、コミット成功を返した直後でもレプリカは旧データを返しえます。準同期は「少なくとも1台は受領済み」を保証するためフェイルオーバー時の損失は防げますが、それと読み取りが最新を返すかは別問題です。受領しただけでまだ適用していないレプリカを読めば、やはり古い値が見えます。
つまり「成功を返した=失わない(耐久性)」と「いま読んで最新が見える(可視性・一貫性)」は別の保証であり、レプリケーション方式が直接決めるのは前者です。後者はトランザクション分離レベルや read-your-writes などのセッション一貫性で別途設計します。最終的に、整合性をどこまで強く要求し、可用性をどこまで犠牲にするかはCAP定理のトレードオフに帰着します。
「3方式の違いを一言で」なら、コミット成功を返す瞬間に変更がどこまで耐久化されているか——非同期=プライマリにflush、準同期=レプリカが受領/書込み、同期=レプリカが永続化。RPOは非同期 > 準同期 > 同期(小さいほど良い)、コミット遅延は逆順。フェイルオーバーの2大事故は**データ損失(追いつき不足)とスプリットブレイン(分岐)**で、後者はフェンシングと過半数クォーラムで封じる、と整理できれば十分です。
まとめ
同期・準同期・非同期を分けるのは、ただ一点「プライマリがコミット成功を返す瞬間に、変更がどこまで耐久化されているか」です。非同期はローカルflushで即返すので速いがフェイルオーバーで未送出ぶんを失い(RPO > 0)、同期はレプリカの永続化まで待つのでRPO=0に近いがレプリカのRTTとfsyncに律速されます。準同期はその中間で、受領か書き込みかという耐久化条件の取り方と、タイムアウト時に非同期へ落ちる窓が安全性を左右します。フェイルオーバーでは昇格レプリカの追いつき不足によるデータ損失と、**旧プライマリ復活による分岐(スプリットブレイン)**が起こり、前者は最進ノードの昇格で緩和、後者はフェンシングと過半数クォーラムで構造的に封じます。RPO=0と分岐防止を同時に得たいなら、過半数の永続化を待つクォーラムコミット(コンセンサスベースHA)に行き着きます。
データベース Article
同期/準同期/非同期レプリケーションとフェイルオーバーを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
レプリケーション
比較で見る軸
難易度: advanced / カテゴリ: データベース / タグ数: 5
導入後に効く点
この瞬間の取り方が RPO/RTO を決める。同期はRPO=0に近づくがプライマリの応答が遠いレプリカの待ちに律速され、非同期は速いがフェイルオーバーで未送出ぶんが消える。準同期は「過半数のうち1台」など耐久化条件を緩めて両者の中間を取る。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- データベース
- タグ数
- 5
判断チェックリスト
- 自社の用途が「レプリケーション / フェイルオーバー」に近いか確認する。
- 強みである「違いは「プライマリがクライアントへコミット成功を返す瞬間に、変更がどこまで耐久化されているか」の一点。非同期はローカル書き込み時点、準同期はレプリカが受領(または書き込み)した時点、同期はレプリカが永続化した時点で返す。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。