# 機能設計書 53-クラスタマネージャ選出

## 概要

本ドキュメントは、OpenSearchにおけるクラスタマネージャ選出機能の設計を記述する。クラスタマネージャ選出は、Raftベースのコンセンサスプロトコルを使用してクラスタのリーダーノードを選出し、フェイルオーバーを実現する機能である。

### 本機能の処理概要

クラスタマネージャ選出機能は、クラスタ内でリーダー（クラスタマネージャ）を選出し、リーダーの障害時にフェイルオーバーを自動的に実行する。Zen2と呼ばれるRaftベースのコンセンサスアルゴリズムを使用し、分散環境での一貫性と可用性を両立する。

**業務上の目的・背景**：分散システムでは、クラスタ全体の状態を管理する単一のリーダーノードが必要である。リーダーの障害時に自動的に新しいリーダーを選出することで、システムの可用性を確保する。

**機能の利用シーン**：
- 新規クラスタの初期起動時にリーダーを選出する場合
- 現在のクラスタマネージャが障害を起こした場合のフェイルオーバー
- ネットワーク分断からの復旧時にリーダーを再選出する場合
- クラスタマネージャノードの計画的な停止・再起動時

**主要な処理内容**：
1. PreVote（事前投票）による選挙開始判断
2. StartJoin（選挙開始）とJoin投票の収集
3. クォーラムに基づくリーダー確定
4. クラスタ状態のパブリッシュとコミット
5. LeaderChecker/FollowersCheckerによる障害検出

**関連システム・外部連携**：DiscoveryModuleと連携してノード発見を行う。ClusterServiceと連携してクラスタ状態を管理する。TransportServiceと連携してノード間通信を行う。

**権限による制御**：クラスタマネージャ選出は内部プロセスであり、直接的なアクション権限は不要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 47 | クラスタヘルス | 参照画面 | クラスタマネージャの状態確認 |
| 49 | ノード情報・統計 | 参照画面 | ノードのロール確認 |

## 機能種別

クラスタ管理 / コンセンサス / 内部プロセス

## 入力仕様

### 主要設定パラメータ

| パラメータ名 | 型 | 必須 | 説明 | デフォルト値 |
|-------------|-----|-----|------|-------------|
| cluster.initial_cluster_manager_nodes | List | Yes* | 初期クラスタマネージャノード | [] |
| cluster.election.strategy | String | No | 選挙戦略 | default |
| cluster.election.initial_timeout | TimeValue | No | 初期選挙タイムアウト | 100ms |
| cluster.election.back_off_time | TimeValue | No | 選挙バックオフ時間 | 100ms |
| cluster.election.max_timeout | TimeValue | No | 最大選挙タイムアウト | 10s |
| cluster.election.duration | TimeValue | No | 選挙期間 | 500ms |
| cluster.fault_detection.leader_check.interval | TimeValue | No | リーダーチェック間隔 | 1s |
| cluster.fault_detection.leader_check.timeout | TimeValue | No | リーダーチェックタイムアウト | 10s |
| cluster.fault_detection.leader_check.retry_count | int | No | リーダーチェックリトライ回数 | 3 |
| cluster.fault_detection.follower_check.interval | TimeValue | No | フォロワーチェック間隔 | 1s |
| cluster.fault_detection.follower_check.timeout | TimeValue | No | フォロワーチェックタイムアウト | 10s |
| cluster.fault_detection.follower_check.retry_count | int | No | フォロワーチェックリトライ回数 | 3 |

*新規クラスタ起動時に必須

### 入力データソース

- クラスタ設定
- ノード間通信（TransportService）
- 永続化された状態（PersistedState）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ClusterState | Object | 更新されたクラスタ状態 |
| ClusterState.nodes.masterNodeId | String | 選出されたクラスタマネージャのノードID |
| CoordinationMetadata.term | long | 現在のterm |
| CoordinationMetadata.lastAcceptedConfiguration | VotingConfiguration | 承認された投票設定 |

### 出力先

- クラスタ状態（全ノードにパブリッシュ）
- ログファイル

## 処理フロー

### 処理シーケンス

```
1. 選挙開始判断
   └─ LeaderCheckerによるリーダー障害検出
   └─ または初期クラスタブートストラップ
2. PreVote（事前投票）
   └─ PreVoteCollector.start()
   └─ 過半数からPreVoteを収集
3. 選挙開始
   └─ ElectionScheduler.scheduleNextElection()
   └─ startElection()
4. Join投票収集
   └─ JoinHelper.sendJoinRequest()
   └─ クォーラムのJoinを収集
5. リーダー確定
   └─ becomeLeader()
   └─ Modeを LEADER に変更
6. クラスタ状態パブリッシュ
   └─ publish()
   └─ 過半数のACKを待機
7. 障害監視開始
   └─ FollowersChecker（リーダー側）
   └─ LeaderChecker（フォロワー側）
```

### フローチャート

```mermaid
flowchart TD
    A[リーダー障害検出/初期起動] --> B[PreVote開始]
    B --> C{過半数のPreVote?}
    C -->|No| D[待機・リトライ]
    D --> B
    C -->|Yes| E[選挙開始]

    E --> F[StartJoin送信]
    F --> G[Join投票収集]
    G --> H{クォーラム達成?}
    H -->|No| I[タイムアウト待ち]
    I --> B
    H -->|Yes| J[becomeLeader]

    J --> K[Mode = LEADER]
    K --> L[クラスタ状態パブリッシュ]
    L --> M{過半数ACK?}
    M -->|No| N[パブリッシュ失敗]
    M -->|Yes| O[コミット完了]

    O --> P[FollowersChecker開始]
    P --> Q[継続的な障害監視]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | クォーラム要件 | 選挙には過半数（N/2+1）の投票が必要 | 常時 |
| BR-02 | Term単調増加 | termは常に単調増加する | 常時 |
| BR-03 | 単一リーダー保証 | 同一termで複数のリーダーは存在しない | 常時 |
| BR-04 | PreVote要件 | 選挙開始前にPreVoteで過半数の承認が必要 | 常時 |
| BR-05 | 指数バックオフ | 選挙失敗時は指数バックオフで再試行 | 選挙失敗時 |
| BR-06 | クラスタマネージャ適格性 | node.masterがtrueのノードのみ選挙に参加 | 常時 |

### 計算ロジック

#### クォーラム計算
```
quorum = (votingNodes.size() / 2) + 1
```

#### 選挙タイムアウト計算
```
timeout = min(initialTimeout * 2^retryCount, maxTimeout) + random(0, backOffTime)
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象 | 操作種別 | 概要 |
|-----|------|---------|------|
| term更新 | PersistedState | UPDATE | 現在のtermを永続化 |
| VotingConfiguration更新 | ClusterState.coordinationMetadata | UPDATE | 投票設定の更新 |
| クラスタマネージャ更新 | ClusterState.nodes | UPDATE | マスターノードIDの更新 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ElectionFailedException | 選挙がタイムアウト | 自動リトライ |
| - | NotMasterException | リーダーでないノードへの書き込み要求 | リーダーノードにリダイレクト |
| - | NodeDisconnectedException | ノード間接続断 | 再接続後に再試行 |

### リトライ仕様

選挙は指数バックオフ（`initial_timeout * 2^n`、最大`max_timeout`）で自動的に再試行される。

## トランザクション仕様

クラスタ状態の更新は2フェーズコミットで行われる：
1. Publish: リーダーがクラスタ状態を全ノードに送信
2. Commit: 過半数のACKを受信後、コミットメッセージを送信

## パフォーマンス要件

- 選挙は通常数百ミリ秒〜数秒で完了
- 障害検出は`fault_detection.*.interval`の設定に依存
- 大規模クラスタではネットワーク遅延を考慮した設定が必要

## セキュリティ考慮事項

- ノード間通信はTLS/SSLで暗号化可能
- 不正なノードの参加を防ぐためのクラスタ名検証
- VotingConfigurationにより投票権を持つノードを制限可能

## 備考

- Zen2はRaftプロトコルのバリエーションを採用
- Coordinatorは3つのMode（CANDIDATE/LEADER/FOLLOWER）を持つ
- VotingConfigExclusionにより特定ノードを投票から除外可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: 状態管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CoordinationState.java | `server/src/main/java/org/opensearch/cluster/coordination/CoordinationState.java` | 選挙状態の管理。term, lastAcceptedState, votingConfigurationを確認 |
| 1-2 | PersistedStateRegistry.java | `server/src/main/java/org/opensearch/cluster/coordination/PersistedStateRegistry.java` | 永続化された状態の管理 |

#### Step 2: コーディネーターを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Coordinator.java | `server/src/main/java/org/opensearch/cluster/coordination/Coordinator.java` | 選出の中心実装。Mode列挙型、startElection()、becomeLeader()を確認 |

**主要処理フロー**:
- **Mode.CANDIDATE**: 選挙中の状態
- **Mode.LEADER**: リーダーとして稼働中
- **Mode.FOLLOWER**: フォロワーとして稼働中

#### Step 3: 選挙プロセスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PreVoteCollector.java | `server/src/main/java/org/opensearch/cluster/coordination/PreVoteCollector.java` | 事前投票の収集 |
| 3-2 | ElectionSchedulerFactory.java | `server/src/main/java/org/opensearch/cluster/coordination/ElectionSchedulerFactory.java` | 選挙スケジューリング（指数バックオフ） |

#### Step 4: 障害検出を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | LeaderChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/LeaderChecker.java` | フォロワーがリーダーを監視 |
| 4-2 | FollowersChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/FollowersChecker.java` | リーダーがフォロワーを監視 |

#### Step 5: クラスタ参加を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | JoinHelper.java | `server/src/main/java/org/opensearch/cluster/coordination/JoinHelper.java` | Join投票の送受信 |
| 5-2 | ClusterBootstrapService.java | `server/src/main/java/org/opensearch/cluster/coordination/ClusterBootstrapService.java` | 初期クラスタのブートストラップ |

### プログラム呼び出し階層図

```
Coordinator
    |
    +-- Mode管理（CANDIDATE/LEADER/FOLLOWER）
    |
    +-- 選挙プロセス
    |     +-- PreVoteCollector.start()
    |     +-- ElectionSchedulerFactory.scheduleNextElection()
    |     +-- startElection()
    |     +-- becomeLeader()
    |
    +-- 障害検出
    |     +-- LeaderChecker（フォロワー側）
    |     +-- FollowersChecker（リーダー側）
    |
    +-- クラスタ状態管理
    |     +-- CoordinationState
    |     +-- publish()
    |     +-- commit()
    |
    +-- 参加処理
          +-- JoinHelper
          +-- ClusterBootstrapService
```

### データフロー図

```
[入力]                          [処理]                              [出力]

障害検出/起動 ----------> Coordinator --------------------------> ClusterState更新
                          |                                         (masterNodeId)
                          +-> PreVoteCollector
                          |     +-> PreVote収集
                          |
                          +-> ElectionScheduler
                          |     +-> 選挙スケジュール
                          |
                          +-> startElection()
                          |     +-> Join収集
                          |
                          +-> becomeLeader()
                          |     +-> Mode = LEADER
                          |
                          +-> publish()
                                +-> クラスタ状態配信
                                +-> ACK収集
                                +-> commit()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Coordinator.java | `server/src/main/java/org/opensearch/cluster/coordination/Coordinator.java` | ソース | コーディネーション中心実装 |
| CoordinationState.java | `server/src/main/java/org/opensearch/cluster/coordination/CoordinationState.java` | ソース | 選挙状態管理 |
| PreVoteCollector.java | `server/src/main/java/org/opensearch/cluster/coordination/PreVoteCollector.java` | ソース | 事前投票収集 |
| ElectionSchedulerFactory.java | `server/src/main/java/org/opensearch/cluster/coordination/ElectionSchedulerFactory.java` | ソース | 選挙スケジューリング |
| LeaderChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/LeaderChecker.java` | ソース | リーダー監視 |
| FollowersChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/FollowersChecker.java` | ソース | フォロワー監視 |
| JoinHelper.java | `server/src/main/java/org/opensearch/cluster/coordination/JoinHelper.java` | ソース | 参加処理 |
| ClusterBootstrapService.java | `server/src/main/java/org/opensearch/cluster/coordination/ClusterBootstrapService.java` | ソース | 初期ブートストラップ |
| PersistedStateRegistry.java | `server/src/main/java/org/opensearch/cluster/coordination/PersistedStateRegistry.java` | ソース | 永続化状態管理 |
| Publication.java | `server/src/main/java/org/opensearch/cluster/coordination/Publication.java` | ソース | クラスタ状態パブリッシュ |
| CoordinationMetadata.java | `server/src/main/java/org/opensearch/cluster/coordination/CoordinationMetadata.java` | ソース | コーディネーションメタデータ |
