# 機能設計書 56-シャードアロケーション

## 概要

本ドキュメントは、OpenSearchにおけるシャードアロケーション機能の設計を記述する。シャードアロケーションは、インデックスのシャード（プライマリおよびレプリカ）をクラスタ内のノード間で配置・再配置する中核機能である。

### 本機能の処理概要

シャードアロケーション機能は、未割り当てシャードのノードへの割り当て、既存シャードの移動（リロケーション）、およびクラスタ全体のバランシングを制御する。AllocationServiceを中心として、複数のAllocationDeciderが連携し、各シャードの最適な配置先を決定する。

**業務上の目的・背景**：分散検索エンジンにおいて、シャードの適切な配置はクエリ性能、データ可用性、およびクラスタの安定性に直結する。ノードの追加・削除、ディスク容量の変化、障害発生時などに、シャードを自動的に再配置することで、システムの可用性と性能を維持する。

**機能の利用シーン**：
- 新規インデックス作成時のプライマリ・レプリカシャードの初期配置
- ノード追加時のシャード再バランシング
- ノード障害時のシャード再割り当て
- ディスク容量超過時のシャード移動
- 手動でのシャード移動・キャンセル（Cluster Reroute API）

**主要な処理内容**：
1. 未割り当てシャードの優先順位付けと配置先決定
2. AllocationDecidersによる配置可否判定
3. BalancedShardsAllocatorによる重み計算とバランシング
4. シャード移動（リロケーション）の実行
5. クラスタ状態の更新とルーティングテーブルの更新

**関連システム・外部連携**：ClusterServiceと連携してクラスタ状態を管理する。GatewayAllocatorと連携して既存シャードデータを検索・リカバリする。

**権限による制御**：`cluster:admin/reroute`アクション権限が必要（手動リルート時）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 47 | クラスタヘルス | 参照画面 | シャードの割り当て状態を確認 |
| 50 | クラスタ設定管理 | 設定画面 | アロケーション設定の変更 |

## 機能種別

クラスタ状態管理 / シャード配置制御

## 入力仕様

### 主要設定パラメータ（クラスタ設定）

| パラメータ名 | 型 | 必須 | 説明 | デフォルト値 |
|-------------|-----|-----|------|-------------|
| cluster.routing.allocation.enable | Enum | No | アロケーション有効化レベル | all |
| cluster.routing.rebalance.enable | Enum | No | リバランス有効化レベル | all |
| cluster.routing.allocation.disk.threshold_enabled | Boolean | No | ディスク閾値チェック有効化 | true |
| cluster.routing.allocation.disk.watermark.low | String | No | 低ウォーターマーク | 85% |
| cluster.routing.allocation.disk.watermark.high | String | No | 高ウォーターマーク | 90% |
| cluster.routing.allocation.disk.watermark.flood_stage | String | No | フラッドステージ | 95% |
| cluster.routing.allocation.balance.shard | Float | No | シャードバランス重み係数 | 0.45 |
| cluster.routing.allocation.balance.index | Float | No | インデックスバランス重み係数 | 0.55 |
| cluster.routing.allocation.balance.threshold | Float | No | リバランス実行閾値 | 1.0 |
| cluster.routing.allocation.concurrent_recoveries | Integer | No | 同時リカバリ数上限 | 2 |

### インデックス設定

| パラメータ名 | 型 | 必須 | 説明 | デフォルト値 |
|-------------|-----|-----|------|-------------|
| index.routing.allocation.enable | Enum | No | インデックス単位のアロケーション有効化 | all |
| index.routing.allocation.include.* | String | No | 配置先ノード包含フィルタ | - |
| index.routing.allocation.exclude.* | String | No | 配置先ノード除外フィルタ | - |
| index.routing.allocation.require.* | String | No | 配置先ノード必須フィルタ | - |

### Cluster Reroute API

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| commands | Array | Yes | アロケーションコマンドのリスト | 有効なコマンド形式 |
| dry_run | Boolean | No | ドライラン | - |
| explain | Boolean | No | 判定理由説明を含める | - |
| retry_failed | Boolean | No | 失敗シャードの再試行 | - |

## 出力仕様

### Cluster Reroute APIレスポンス

| 項目名 | 型 | 説明 |
|--------|-----|------|
| acknowledged | boolean | リクエスト受理 |
| state | Object | 更新後のクラスタ状態 |
| explanations | Array | 実行結果と説明 |

### 出力先

- クラスタ状態（ClusterState）: 全ノードに伝播
- REST APIレスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. アロケーション処理開始
   └─ AllocationService.reroute()
2. 自動レプリカ拡張チェック
   └─ adaptAutoExpandReplicas()
3. RoutingNodes構築
   └─ ミュータブルなルーティングノード作成
4. 既存シャード割り当て
   └─ ExistingShardsAllocator（プライマリ→レプリカ）
5. シャードアロケータ処理
   └─ BalancedShardsAllocator.allocate()
6. クラスタ状態更新
   └─ buildResultAndLogHealthChange()
```

### フローチャート

```mermaid
flowchart TD
    A[アロケーション開始] --> B[RoutingNodes構築]
    B --> C[既存シャード割り当て]
    C --> D[プライマリシャード処理]
    D --> E[レプリカシャード処理]

    E --> F[ShardsAllocator.allocate]
    F --> G[未割り当てシャード配置]
    G --> H[シャード移動判定]

    H --> I{canRemain?}
    I -->|No| J[シャード移動実行]
    I -->|Yes| K[バランシング処理]
    J --> K

    K --> L{閾値超過?}
    L -->|Yes| M[リバランス実行]
    L -->|No| N[クラスタ状態更新]
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | プライマリ優先 | プライマリシャードはレプリカより先に割り当て | 常時 |
| BR-02 | 同一ノード禁止 | 同一シャードのプライマリとレプリカは異なるノードに配置 | 常時 |
| BR-03 | 低ウォーターマーク | 使用率85%以上のノードには新規シャード割り当て禁止 | disk.threshold_enabled=true |
| BR-04 | 高ウォーターマーク | 使用率90%以上のノードからシャード移動 | disk.threshold_enabled=true |
| BR-05 | フィルタ適用順序 | require→include→excludeの順で適用 | フィルタ設定時 |
| BR-06 | リバランス閾値 | ノード間の重み差がthreshold以上の場合のみリバランス | 常時 |

### 計算ロジック（重み関数）

```
weight(node, index) = theta0 * weightShard + theta1 * weightIndex
weightShard = node.numShards() - avgShardsPerNode
weightIndex = node.numShards(index) - avgShardsPerNode(index)
```

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

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

| 操作 | 対象 | 操作種別 | 概要 |
|-----|------|---------|------|
| シャード割り当て | ClusterState.routingTable | UPDATE | シャードルーティング情報更新 |
| メタデータ更新 | ClusterState.metadata | UPDATE | インデックスメタデータ更新 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | AllocationStatus.NO_VALID_SHARD_COPY | 有効なシャードコピーなし | データ復旧またはシャード再作成 |
| - | AllocationStatus.DECIDERS_NO | すべてのDeciderがNO | 設定確認し制約を緩和 |
| - | AllocationStatus.DECIDERS_THROTTLED | スロットリング | 時間をおいて自動再試行 |

### リトライ仕様

アロケーションはクラスタ状態変更イベントで自動再トリガー。失敗シャードはMaxRetryAllocationDeciderで制御（デフォルト5回）。

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

クラスタ状態の更新はClusterStateUpdateTaskとしてアトミックに実行。All-or-nothing。

## パフォーマンス要件

- アロケーションはクラスタマネージャノードで実行
- `cluster.routing.allocation.balanced_shards_allocator.allocator_timeout`でタイムアウト設定可能

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

- Cluster Reroute APIには`cluster:admin/reroute`権限が必要
- ノードフィルタ設定により特定ノードへのシャード配置を制御可能

## 備考

- AllocationDecidersは複数のDeciderの判定を集約
- BalancedShardsAllocatorがデフォルトのシャードアロケータ

---

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

### 推奨読解順序

#### Step 1: 中核サービス

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AllocationService.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/AllocationService.java` | reroute(), applyStartedShards()メソッド |
| 1-2 | RoutingAllocation.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/RoutingAllocation.java` | アロケーションコンテキスト |

#### Step 2: Decider

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AllocationDecider.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/decider/AllocationDecider.java` | 抽象基底クラス |
| 2-2 | AllocationDeciders.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/decider/AllocationDeciders.java` | コンポジットクラス |
| 2-3 | DiskThresholdDecider.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/decider/DiskThresholdDecider.java` | ディスク閾値判定 |

#### Step 3: Allocator

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | BalancedShardsAllocator.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/allocator/BalancedShardsAllocator.java` | バランスドアロケータ |
| 3-2 | LocalShardsBalancer.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/allocator/LocalShardsBalancer.java` | バランシングロジック |

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AllocationService.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/AllocationService.java` | ソース | 中核サービス |
| AllocationDeciders.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/decider/AllocationDeciders.java` | ソース | Decider集約 |
| BalancedShardsAllocator.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/allocator/BalancedShardsAllocator.java` | ソース | アロケータ |
| DiskThresholdDecider.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/decider/DiskThresholdDecider.java` | ソース | ディスク閾値判定 |
| EnableAllocationDecider.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/decider/EnableAllocationDecider.java` | ソース | アロケーション有効化 |
| FilterAllocationDecider.java | `server/src/main/java/org/opensearch/cluster/routing/allocation/decider/FilterAllocationDecider.java` | ソース | ノードフィルタ判定 |
