Raft 状態遷移図
Raft の Follower・Candidate・Leader がどの条件で切り替わるかを、選挙タイムアウトとログ複製の流れに沿って図解で追えます。状態遷移の全分岐を文章と表で腹落ちさせます。
- 1.Raft の各ノードは Follower・Candidate・Leader の3状態を取り、状態を切り替える引き金は選挙タイムアウト・過半数の獲得・より大きい term の観測の3つに集約される。
- 2.Follower は心拍が途絶えると Candidate に昇格して選挙を始め、過半数票を得れば Leader に、別 Leader を見つければ Follower に戻る。誰も過半数に届かなければランダム化タイムアウトで再選挙する。
- 3.Leader は AppendEntries で心拍とログ複製を兼ね、より新しい term を観測した瞬間に即 Follower へ降格する。これにより同一 term の二重 Leader が構造的に排除される。
3状態と遷移を引き起こす3つの引き金
Raft では、クラスタ内の各ノードが常に Follower・Candidate・Leader のいずれか1つの状態にいます。状態の全体像と詳しい合意の原理は分散合意アルゴリズム(Paxos / Raft)で扱いました。本稿はその続きとして、どの条件でどの状態へ移るのかという遷移そのものを精密に追います。
まず押さえるべきは、状態を切り替える引き金が次の3種類しかないことです。
- 選挙タイムアウト(election timeout): 一定時間 Leader から有効な通信が来ないと発火する。
- 過半数の獲得(majority vote): Candidate が
floor(N/2)+1票を集めた瞬間に発火する。 - より大きい term の観測: 自分の term より大きい term を持つメッセージを見た瞬間に発火する。
この3つだけで、Raft の全遷移が説明できます。逆に言えば、ここに当てはまらない理由で勝手に状態が変わることはありません。
状態遷移の全分岐
各状態を起点に、どの引き金でどこへ向かうかを一覧にします。
| 起点状態 | 引き金 | 遷移先 | 起こること |
|---|---|---|---|
| Follower | 選挙タイムアウト(心拍が途絶) | Candidate | term を+1し自分に投票して RequestVote を送る |
| Candidate | 過半数の票を獲得 | Leader | 即座に心拍を送り出し書き込み窓口になる |
| Candidate | 別 Leader(同等以上の term)から AppendEntries 受信 | Follower | 正当な Leader を認め降格する |
| Candidate | 選挙タイムアウト(票が割れて未決着) | Candidate | term を更に+1し選挙をやり直す(再立候補) |
| Leader | 自分より大きい term を観測 | Follower | 自分が古いと悟り即降格する |
| Candidate / Leader | 自分より大きい term を観測 | Follower | term を相手に合わせ Follower へ戻る |
注目点は、Leader からの遷移先が Follower しか無いことです。Leader が Candidate に直接戻る経路はありません。一度 Leader になったノードは、より新しい term を見て降格するか、自分が落ちるまで Leader であり続けます。
起動から定常までの順序
ノードが起動してからの流れを、時系列で追います。
- 全ノードは Follower として起動する。Leader も Candidate もいない初期状態。
- どの Follower も Leader からの心拍を受けないため、最初にタイムアウトしたノードが Candidate へ。term を
0→1に上げ、自分に1票投じ、全ノードへRequestVote(term=1)を送る。 - 他ノードは「同じ term でまだ誰にも投票していなければ賛成」という規則(1 term 1票)に従い投票する。
- Candidate が過半数の票を集めれば Leader へ昇格。直ちに空の
AppendEntries(心拍)を送り、自分が Leader だと全員に知らせる。 - 心拍を受けた他ノードは Follower のままタイマーをリセットし、定常状態に入る。
起動直後の選挙(N=3, 過半数=2)
全員 Follower
│ 最初に election timeout したノードX
▼
X: Candidate (term 0→1, 自分に1票)
X ──RequestVote(term=1)──▶ Y, Z
Y, Z: この term で未投票 → 賛成
X: 2票(自分+Y)= 過半数 → Leader 確定
X ──AppendEntries(heartbeat)──▶ Y, Z
Y, Z: Follower のままタイマーリセット
全 Follower の選挙タイムアウトが同じ値だと、心拍途絶時に複数ノードがほぼ同時に Candidate へ昇格し、票が割れて誰も過半数に届かない「スプリットボート」が起きやすくなります。Raft は各ノードのタイムアウトを一定範囲(例: 150〜300ms)でランダムに選び直すことで立候補のタイミングをずらし、ふつう最初の1ノードだけが立候補して一発で決まるよう仕向けます。これが選挙の活性(いつかは決まる)を支えます。
選挙が決着しないときの再選挙ループ
票が割れた場合の遷移が、状態遷移図でつまずきやすい点です。Candidate は3つの結末を持ちます。
- 過半数を得る → Leader へ昇格。
- 別 Leader を見つける(同等以上の term の AppendEntries を受信)→ Follower へ降格。
- どちらも起きないまま再びタイムアウト → term を更に+1してもう一度 Candidate として選挙をやり直す。
3番目が「Candidate → Candidate」の自己ループです。これは無限ループに見えますが、タイムアウトがランダム化されているため、繰り返すうち最初に立候補した1ノードだけが他より早く動く確率が高まり、いずれ過半数が成立して抜け出します。
スプリットボートと再選挙
term=2: A も B も同時に Candidate
A → A,? の票, B → B,? の票 (3台目が割れる/未着)
どちらも過半数(2)未満 → 両者タイムアウト
A: term 2→3 で再立候補(ランダムに先んじる)
A が過半数 → Leader、B は A の心拍で term=3 を観測し Follower へ
Leader の定常動作:心拍とログ複製は同じ経路
Leader になったノードの動作は、状態遷移を「維持する」働きと「データを進める」働きを1つのメッセージ AppendEntries に統合している点が要点です。
- 空の AppendEntries = 心拍。Follower のタイマーをリセットし、選挙タイムアウトの発火を防いで Leader の地位を保つ。
- エントリ入りの AppendEntries = ログ複製。クライアントのコマンドをログ末尾に追記して送り、過半数に複製された時点でコミットとする。
つまり Leader は「自分の正当性の維持」と「ログの前進」を別チャネルに分けず、同じ仕組みで回します。Follower 側から見れば、有効な AppendEntries が届く限りタイマーは切れず、状態は Follower のまま安定します。ログ複製の整合規則(Log Matching)の詳細は分散合意アルゴリズム(Paxos / Raft)を参照してください。コミット済みエントリを耐久化する先行書き込みの考え方は先行書き込みログ(WAL)と地続きです。
定常状態のログ複製
Client ──command──▶ Leader
Leader: ログ末尾に (term, index, command) を追記
Leader ──AppendEntries(entries=[...])──▶ Followers
Followers: 直前エントリの (term, index) が一致 → 追記しACK
Leader: 過半数のACK → そのindexを committed に
Leader: 状態機械に適用しClientへ結果返却(次の心拍でcommitIndexを伝搬)
状態遷移で最も強い規則が「自分より大きい term を見たら、どの状態だろうと即 Follower に戻り term を相手に合わせる」です。古い Leader がネットワーク分断から復帰し、その間に新しい term の Leader が立っていた場合、古い Leader は新 Leader の心拍に乗った大きい term を見た瞬間に降格します。これにより、同一 term に Leader が2人存在する状態は構造的に発生しません。term は単調増加し、各 term の Leader は高々1人です。
なぜ Leader → Candidate の直接遷移が無いのか
この非対称性は安全性の帰結です。Leader が「自分は古いかもしれない」と疑う唯一の根拠は、より大きい term の観測です。そしてより大きい term を観測したノードは、定義上まず Follower に戻って term を同期しなければなりません。Candidate になるには改めて選挙タイムアウトを待つ必要があり、いきなり立候補はできません。
もし Leader が Follower を経ずに Candidate へ飛べると、term の同期前に新たな選挙を始めてしまい、古い情報のまま二重 Leader を生むリスクが出ます。「降格は必ず Follower 経由」という制約が、term 同期を強制し、安全性を守っています。
状態遷移は「3状態 × 3引き金」で暗記より理解が効きます。押さえるべき非対称性は2つ。(1) Leader からの遷移先は Follower のみ(Candidate へは戻れない)。(2) より大きい term の観測は、現在の状態に関わらず無条件に Follower へ降格させる。この2点と「心拍途絶→Candidate→過半数→Leader」の基本ループを言えれば、状態遷移図は再現できます。
まとめ
Raft の状態遷移は Follower・Candidate・Leader の3状態を、選挙タイムアウト・過半数獲得・より大きい term の観測という3つの引き金だけで切り替えます。Follower は心拍途絶で Candidate へ昇格し、過半数を得れば Leader、別 Leader を見れば Follower へ。票が割れればランダム化タイムアウトで再選挙します。Leader は AppendEntries で心拍とログ複製を兼ね、より大きい term を見た瞬間だけ Follower へ降格します。Leader→Candidate の直接経路が無いこと、より大きい term は無条件で降格させることが、同一 term の二重 Leader を構造的に排除し、合意の安全性を支えます。リーダー選出を冗長化する位置づけは2相コミット(2PC)と分散トランザクションやレプリケーションとシャーディングの議論ともつながります。
データベース Article
Raft 状態遷移図を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
Raft
比較で見る軸
難易度: advanced / カテゴリ: データベース / タグ数: 5
導入後に効く点
Follower は心拍が途絶えると Candidate に昇格して選挙を始め、過半数票を得れば Leader に、別 Leader を見つければ Follower に戻る。誰も過半数に届かなければランダム化タイムアウトで再選挙する。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- データベース
- タグ数
- 5
判断チェックリスト
- 自社の用途が「Raft / 状態遷移」に近いか確認する。
- 強みである「Raft の各ノードは Follower・Candidate・Leader の3状態を取り、状態を切り替える引き金は選挙タイムアウト・過半数の獲得・より大きい term の観測の3つに集約される。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。