スプリットブレインとフェンシング・STONITH
ネットワーク分断で複数ノードが同時に主を名乗ると、二重書き込みでデータが壊れます。クォーラム・フェンシング・STONITH がなぜ破損を止められるのか、原理から腹落ちできます。
- 1.スプリットブレインは、ネットワーク分断で互いを死んだと誤認した複数ノードが同時に主(プライマリ)を名乗る状態。両方が書き込むとデータが分岐し、自動復旧では戻せない破損になる。
- 2.防止の本質は『過半数を取れた側だけが書ける』こと。奇数台のクォーラムや偶数台のクォーラムディスク/タイブレーカで多数派を一意に決め、少数派は自発的に降格する。
- 3.誤認や遅延で旧主が書き続けるのを物理的に止めるのがフェンシング。電源やストレージI/Oを強制遮断するのが STONITH で、生死が曖昧でも『確実に書けない状態』を作って安全側に倒す。
スプリットブレインとは何が壊れるのか
スプリットブレイン(split-brain、脳分裂) とは、ネットワーク分断などで互いの生存を確認できなくなったノード群が、それぞれ「相手は死んだ。自分が主だ」と判断して同時にプライマリとして振る舞ってしまう 状態です。名前の通り、1つだった「頭脳(権限)」が2つに割れます。
なぜ危険かは、書き込みの可能なノードが2つになる点に尽きます。クライアントAは旧主に、クライアントBは新主に書き込み、両者は互いの更新を知りません。分断が解けた瞬間、2つの履歴は矛盾したまま合流し、どちらを正とも決められません。これは単なる遅延(同期・準同期・非同期レプリケーションで扱う複製ラグ)とは質が違い、因果的に独立した2系列のデータが両方コミット済みという、自動では戻せない破損です。
高可用性のためのフェイルオーバー機構そのものが、スプリットブレインの引き金になります。監視ノードが旧主を「死んだ」と誤認して新主を昇格させたものの、旧主は実は生きていて分断されていただけ——という状況では、2つの主が同時に書ける 最悪の状態が生まれます。可用性を上げるための仕組みが、条件次第で整合性を破壊しうる点が核心です。
根本原因:障害検知は「死」と「分断」を区別できない
スプリットブレインが避けがたい理由は、非同期ネットワーク上では「ノードの停止」と「ネットワーク分断」を原理的に見分けられない からです。タイムアウトで「応答が来ない」ことは分かっても、その原因が相手のクラッシュなのか、経路の切断なのか、相手が GC やスワップで一時停止しているだけなのかは、観測側からは判別不能です。
旧主Pから見える世界: フォロワーFと監視Wが落ちた? → 自分が主を続ける
監視Wから見える世界: 主Pが落ちた → Fを新主に昇格
↑ 同じ「無応答」を双方が逆向きに解釈する
この曖昧さは、保守的に待てば可用性を、楽観的に昇格すれば整合性を犠牲にする——どちらかを選ばざるを得ません。これはCAP 定理が言う「分断(P)の下では一貫性(C)と可用性(A)を同時には満たせない」を、運用の現場語に翻訳したものに他なりません。だから対策は「検知を完璧にする」方向ではなく、「誤認しても破損しない構造を作る」方向に進みます。
第一の防壁:クォーラムで主を一意に決める
最も基本的な防止策は、過半数(クォーラム、定足数)を取れた側だけが主になれる という規則です。N 台のクラスタで floor(N/2)+1 台の同意を得た側だけが書き込みを許され、過半数に届かない少数派は自発的に主から降りる(self-fencing)。
これが効く理由は集合の交わりにあります。任意の2つの過半数集合は必ず1台以上で重なるため、2つの異なるグループが同時に過半数を主張することは数学的に不可能です。分断で {A,B,C} と {D,E} に割れたら(N=5)、前者だけが3台で過半数を満たし主になれ、後者は2台しかないので降格します。この原理は分散合意(Paxos / Raft)のリーダー選出やクォーラム整合性(R+W>N)とまったく同じ骨格です。
過半数で守れる以上、クラスタは奇数台で組むのが基本です。N 台は floor((N-1)/2) 台の故障に耐えます(3→1、5→2、7→3)。偶数台は故障耐性が増えない一方、ちょうど半々に割れるとどちらも過半数を取れず両側が降格=全停止、あるいは票割れのリスクだけ増えます。可用性を保ちつつ二重主を防ぐには、奇数の投票者を置くのが構造的に有利です。
偶数台や2ノードを救う:クォーラムディスクとタイブレーカ
ノードが2台しかない(プライマリ+スタンバイ)構成や、ちょうど半々に割れうる偶数台では、純粋な多数決が機能しません。そこで奇数番目の票を外部に置くのがクォーラムディスク/タイブレーカの発想です。
- クォーラムディスク(quorum disk): 両ノードから見える共有ストレージ上に小さな投票領域を置き、「最後に主を名乗ったのは誰か」を SCSI 予約などで排他的に記録する。分断後にこのディスクを先に確保できた側だけが主を名乗れ、もう一方はディスクを取れず降格する。ディスクが第三の投票者として機能します。
- ウィットネス/タイブレーカ(witness, arbiter): データは持たないが投票だけを担う軽量ノードを別の障害ドメインに置く。2ノード+ウィットネスで実質3票となり、分断時にウィットネスと連絡できた側が過半数(2票)を取れます。MongoDB の arbiter や各種クラスタの witness がこれにあたります。
| 方式 | 票の出どころ | 向く構成 | 注意点 |
|---|---|---|---|
| 奇数台クォーラム | ノード自身の多数決 | 3台以上の奇数クラスタ | 偶数・2台では機能しない |
| クォーラムディスク | 共有ストレージの排他予約 | 共有ストレージ前提の2台 | ディスク自体が単一障害点になりうる |
| ウィットネス/arbiter | 投票専用の軽量ノード | 2データノード+第三者 | ウィットネスは別障害ドメインに置く |
ウィットネスやクォーラムディスクを主・副と同じスイッチや同じ電源系に置くと、その共通部分が落ちたときに票源ごと巻き込まれ、タイブレークが働きません。第三の票は必ず独立した障害ドメイン(別ラック・別 AZ・別電源)に置くこと。さもないと「3票あるはずが実質1点で連鎖故障」になります。
クォーラムだけでは足りない理由とフェンシング
過半数を取れた側だけが主になれても、降格すべき旧主が本当に書き込みをやめた保証はありません。旧主が長い GC で固まり、自分が少数派に転落したことに気づかないまま復帰し、古い権限のまま遅延した書き込みを発行する——いわゆる ゾンビ主/遅延ライタ問題 が残ります。論理的な合意は「誰が主か」を決められても、すでに飛んでいる I/O や、認識が遅れたプロセスまでは止められないのです。
そこで必要になるのがフェンシング(fencing、隔離) です。フェンシングとは、降格対象のノードが共有リソース(ストレージ・仮想IP・クライアント接続)へアクセスできない状態を能動的に作り出す こと。代表的な技法は2種類です。
- リソースフェンシング: 共有ストレージ側で旧主の I/O を拒否する。SCSI Persistent Reservation で予約鍵を奪い、旧主の書き込みコマンドをストレージが弾く方式が典型。NetworkのレベルでVIPを剥がす、スイッチのポートを落とすのもこれに含まれます。
- フェンシングトークン: 主が昇格するたびに単調増加する番号(トークン) を発行し、ストレージやロックサービスは過去に見た最大トークンより小さい書き込みを拒否 する。遅れて届いた旧主の書き込みは小さいトークンを持つため自動的に弾かれます。
ゾンビ主の書き込みは、発行時点では正当な権限で出されたものです。これを止めるには、受け手側が「いつの権限か」を判定できねばなりません。単調増加トークン(Raft の term や ZooKeeper の zxid に相当)を書き込みのたびに照合し、古い番号を拒否すれば、たとえ旧主が生きていても、新主が一度でも大きい番号で書いた後はその旧主は二度と書けません。送り手の生死に依存せず受け手側で安全を担保するのが要点です。
STONITH:生死が曖昧なら確実に殺す
トークンによる受け手側の拒否は強力ですが、ストレージやロック層がトークン照合に対応している必要があり、対応しない既存システム(共有ディスク上のファイルシステムなど)では使えません。そこで Linux-HA / Pacemaker 系クラスタが採るのが、最も力ずくで確実な手段——STONITH(Shoot The Other Node In The Head、もう一方のノードを撃ち抜く) です。
STONITH は、疑わしいノードを電源レベルで強制的に落とす(または隔離する) ことで、「そのノードはもう絶対に何も書けない」という状態を確定させます。生きているか死んでいるか分からないなら、確実に死なせてから先へ進む。曖昧さを残さないのが思想です。
STONITH の流れ(Pacemaker の例)
1. クラスタが旧主Pを「応答なし」と判定
2. 新主へフェイルオーバーする前に、まずPへ STONITH 実行
3. フェンスデバイス(IPMI/iLO, スマートPDU, ハイパーバイザAPI)が
Pの電源を強制オフ/リセット
4. 「Pは確実に停止した」と確認できて初めて Fを主に昇格
↑ この順序が肝。撃ち抜く前に昇格すると二重主になる
フェンスデバイスには、サーバーの管理ポート(IPMI / iLO / DRAC)、ネットワーク制御の スマート PDU(電源タップ)、クラウドやハイパーバイザのインスタンス停止 API が使われます。重要なのは、これらが疑わしいノード自身の協力を一切必要としない点です。旧主が固まっていようと応答しなかろうと、外側から電源を断てば確実に黙らせられます。
試験・設計で問われる急所は順序です。「フェンシング(STONITH)が成功した」と確認できるまで、新主の昇格や共有リソースの引き継ぎを始めてはいけません。撃ち抜く前に昇格すれば、旧主が生きている間は二重主になり破損します。STONITH が安全なのは「先に確実に止める→止まったと確認→それから引き継ぐ」という直列順序を守るからです。Pacemaker が STONITH 未設定のクラスタを警告するのはこのためです。
STONITH は強力ですが万能ではありません。フェンスデバイス自体(IPMI ポートや PDU)が分断と同時に到達不能になると、クラスタは「相手を確実に止められない」ため安全側に倒して停止します(撃てない以上、昇格は危険なので動けない)。これは破損よりはるかにマシな挙動ですが、可用性は犠牲になります。また、互いを同時に撃ち合うフェンスレース(fence race) で両ノードが落ちる事故もあり、遅延設定や優先順位で先撃ちを一意にする配慮が要ります。
まとめ
スプリットブレインは、ネットワーク分断で「死」と「分断」を区別できない ために複数ノードが同時に主を名乗り、二重書き込みで自動復旧不能な破損を生む状態です。防止は二段構えで、まずクォーラム(奇数台の過半数、偶数・2台ではクォーラムディスクやウィットネスで第三の票を補う)が主を一意に決め、過半数を取れない少数派を自発的に降格させます。しかし論理的合意だけではゾンビ主の遅延書き込みを止められないため、フェンシング(SCSI 予約や単調増加トークンによる受け手側拒否)と、最も確実な STONITH(電源・I/O の強制遮断)で「旧主は物理的に書けない」状態を作ります。鍵は常に先に確実に止めてから引き継ぐ 順序で、これはCAP 定理・分散合意・クォーラム整合性と同じ「過半数の交わり」の原理に貫かれています。
データベース Article
スプリットブレインとフェンシング・STONITHを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
分散システム
比較で見る軸
難易度: advanced / カテゴリ: データベース / タグ数: 5
導入後に効く点
防止の本質は『過半数を取れた側だけが書ける』こと。奇数台のクォーラムや偶数台のクォーラムディスク/タイブレーカで多数派を一意に決め、少数派は自発的に降格する。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- データベース
- タグ数
- 5
判断チェックリスト
- 自社の用途が「分散システム / 高可用性」に近いか確認する。
- 強みである「スプリットブレインは、ネットワーク分断で互いを死んだと誤認した複数ノードが同時に主(プライマリ)を名乗る状態。両方が書き込むとデータが分岐し、自動復旧では戻せない破損になる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。