NVMe PRのFencingがおもしろい:旧Brokerに交代を伝えず、書き込みだけを止める
読んだもの 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の心がけではなく、ストレージだ。 ...