読んだもの
Alibaba Cloudの阿里云云原生チームによる、RocketMQの高可用性の記事(出典は末尾)。生成AIと一緒に読んで整理したメモで、記事本文は自分でも開いて確認した。細部(実測値や予約種別など)は追えていないので、ここでは設計の発想だけ書く。
そもそも何が問題か
Active/Standbyで、Broker AからBroker Bへ切り替えたい。ただ、Aが応答しないからといって、Aが止まっているとは限らない。ネットワーク分断やI/Oハングで、AもBも「自分がActiveだ」と思って同じデータを書くと、Split-Brainでデータが壊れる。
「BがActiveになったとAに通知すればいい」と最初は思う。でも通知が届かないから困っているのであって、リースや分散ロックを足しても、失効を認識できない旧ノードは残る。
旧ノードが交代を認識することに依存する設計は、障害時にいちばん当てにならない。
NVMe PRでどう解くか
NVMe Persistent Reservation(PR)は、ストレージ側で「書き込める保持者」を決める仕組み。保持者以外の書き込みは、デバイスが拒否する。
記事の構成では、Multi-Attachで新旧ノードから同じディスクを見えるようにしておき、障害時に新ノードがPRを奪う。つまり、
- Multi-Attach:同じディスクが見える(書き手の制限はしない)
- NVMe PR:書ける人を一人に絞る
という役割分担になる。旧Brokerのプロセスが生きていても、交代を知らなくても、書き込みはストレージ側で止まる。
流れを図にするとこうなる(理解用の簡略図で、実際の実装手順そのままではない)。
【通常時】
Broker A (Master) Broker B (Shadow)
│ WRITE可能 │ データ領域は未マウント
│ │ leaseを読むだけ
▼ ▼
┌─────────────────────────────────────┐
│ 共有ブロックストレージ │
│ NVMe PR: Aが書き込み保持者 │
└─────────────────────────────────────┘
【障害発生】
Broker A Broker B
│ 応答なし │ leaseが進まないことを検知
│ ※実は生きているかも │
│ ※交代を知らない ▼
│ PRを奪う(preempt)
▼ ▼
┌─────────────────────────────────────┐
│ 共有ブロックストレージ │
│ A: WRITE拒否 ✕ B: WRITE許可 ○ │
└─────────────────────────────────────┘
【引き継ぎ後】
Broker A Broker B
│ 旧保持者 │ 新保持者
│ WRITEしても拒否される │ キャッシュ処理 → マウント
│ │ → journal/WAL回復
│ ▼
│ サービス再開
Aは交代を知らないまま動いていてもいい。止めているのはAの心がけではなく、ストレージだ。
交代を確実に伝える仕組みではなく、交代を知らない旧Brokerでもデータを壊せなくする仕組み。 ここが一番おもしろかった。通信の問題を、通信ではなくストレージのアクセス制御に移して消している。
FencingとRecoveryは別もの
「書き込みを止めたなら、それで整合性は保てるのでは?」と最初は思った。でも守っている時間軸が違う。
| 守るもの | 担当 | |
|---|---|---|
| Fencing | 交代後、旧所有者にこれ以上壊させない | NVMe PR(ストレージ) |
| Recovery | 交代時点で残っている未完了の状態を整える | ファイルシステムのjournal回復、RocketMQのログ回復 |
Fencing:これ以上、旧所有者にデータを壊させない。 Recovery:すでに残っている状態を整理する。
ストレージは「どのメッセージが正しいか」を判断しない。そこはファイルシステムとアプリの仕事。記事ではキャッシュ破棄もこの流れに入っていて、古い状態を新Brokerが使わないための手当てとして位置づけられている。
ついでに:ShadowはSlaveではない
記事に出てくるShadow Brokerは、Slave Brokerとは違う。Slaveは業務データを複製して持つが、Shadowは平時はデータ領域をマウントせず、共有ディスク上のleaseを見張るだけ。故障時に元のディスクの書き込み権を取って引き継ぐ。
なお「複製しない」はRocketMQのサービス層の話で、ディスク自体の冗長性が不要になるわけではない。共有ディスクが壊れた場合は、この方式の守備範囲外。
まとめ
- 「古いノードに新しい状態を知らせる」のではなく、「古い状態を信じたまま動いても、共有データを変更できなくする」
- 役割分担が明確:Fencing=ストレージ、Recovery=ファイルシステム/アプリ
- Fencingだけで全部解決するわけではない(回復処理も、共有ストレージの可用性も別途必要)
通知の成功を期待するのではなく、通知が失敗しても壊れないようにする。それがFencingの核心だと思う。
参考
- 金融通(阿里云云原生)「Multi-Attach + NVMe PR:RocketMQ 如何用协议级 Fencing 避免脑裂?」SegmentFault、2026年8月 — https://segmentfault.com/a/1190000048183964
- 同内容の論文(FSE 2026 Industry Papers、アブストラクトのみ確認)— https://conf.researchr.org/details/fse-2026/fse-2026-industry-papers/25/Replication-Free-Failover-Protocol-Fenced-Takeover-for-Stateful-Services