# 機能設計書 58-重み付きルーティング

## 概要

本ドキュメントは、OpenSearchにおける重み付きルーティング機能の設計を記述する。重み付きルーティングは、アウェアネス属性（ゾーン等）に基づいてトラフィックを重み付けで分散する機能である。

### 本機能の処理概要

重み付きルーティング機能は、特定のアウェアネス属性（例：zone）の各値に対して重みを設定し、検索リクエストをその重みに基づいて分散する。重み0の属性値にはトラフィックがルーティングされない。

**業務上の目的・背景**：マルチゾーン構成のOpenSearchクラスタにおいて、特定のゾーンへのトラフィックを制御する必要がある。メンテナンス時のゾーン切り離しや、ゾーン間の負荷調整、障害対応時のトラフィック迂回などに使用される。

**機能の利用シーン**：
- 特定ゾーンのメンテナンス前のトラフィック除外
- ゾーン間の負荷分散調整
- デコミッション前の重み0設定（必須前提条件）
- フェイルオーバー時のトラフィック制御

**主要な処理内容**：
1. WeightedRoutingMetadataのクラスタメタデータへの登録
2. 属性値ごとの重み設定（0.0〜1.0+）
3. アウェアネス属性・フォースアウェアネス属性の検証
4. デコミッション状態との整合性チェック

**関連システム・外部連携**：OperationRoutingと連携してシャード選択時に重みを適用する。DecommissionServiceと連携してデコミッション前に重み0設定を必須とする。

**権限による制御**：
- 重み設定: `cluster:admin/routing/awareness/weights/put`
- 重み取得: `cluster:admin/routing/awareness/weights/get`
- 重み削除: `cluster:admin/routing/awareness/weights/delete`

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 47 | クラスタヘルス | 参照画面 | 重み設定後のクラスタ状態確認 |
| 54 | ノードデコミッション | 連携機能 | デコミッション前に重み0を設定 |

## 機能種別

クラスタ管理 / トラフィック制御

## 入力仕様

### REST API

#### 重み設定
- エンドポイント: `PUT /_cluster/routing/awareness/{attribute}/weights`
- アクション名: `cluster:admin/routing/awareness/weights/put`

#### 重み取得
- エンドポイント: `GET /_cluster/routing/awareness/{attribute}/weights`
- アクション名: `cluster:admin/routing/awareness/weights/get`

#### 重み削除
- エンドポイント: `DELETE /_cluster/routing/awareness/weights`
- アクション名: `cluster:admin/routing/awareness/weights/delete`

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| attribute | String | Yes | アウェアネス属性名（例: zone） | awareness属性として設定済み |
| weights | Object | Yes | 属性値と重みのマップ | 全ての属性値を含む |
| _version | long | No | 楽観的ロック用バージョン | 現在のバージョンと一致 |

### リクエストボディ例

```json
{
  "zone-a": 1.0,
  "zone-b": 1.0,
  "zone-c": 0.0,
  "_version": 1
}
```

### 入力データソース

- ClusterState
- AwarenessAllocationDecider設定
- DecommissionAttributeMetadata

## 出力仕様

### 重み設定レスポンス

| 項目名 | 型 | 説明 |
|--------|-----|------|
| acknowledged | boolean | リクエストが受理されたか |

### 重み取得レスポンス

| 項目名 | 型 | 説明 |
|--------|-----|------|
| weights | Object | 属性値と重みのマップ |
| _version | long | 現在のバージョン |

### 出力先

- REST APIレスポンス（JSON形式）
- ClusterState.metadata.weightedRoutingMetadata

## 処理フロー

### 処理シーケンス

```
1. 重み設定リクエスト受信
   └─ TransportAddWeightedRoutingAction
2. バリデーション
   └─ アウェアネス属性の検証
   └─ 全属性値の重み指定チェック
   └─ デコミッション状態との整合性チェック
   └─ バージョン競合チェック
3. WeightedRoutingMetadata更新
   └─ ClusterStateUpdateTaskとして実行
4. クラスタ状態更新
   └─ 全ノードに伝播
```

### フローチャート

```mermaid
flowchart TD
    A[重み設定リクエスト] --> B{属性名検証}
    B -->|無効| ERR1[ActionRequestValidationException]
    B -->|有効| C{全属性値の重みが指定されているか?}

    C -->|No| ERR2[UnsupportedWeightedRoutingStateException]
    C -->|Yes| D{半数以上が重み0?}

    D -->|Yes| ERR3[バリデーションエラー]
    D -->|No| E{デコミッション中?}

    E -->|Yes| F{デコミッション属性の重みが0?}
    E -->|No| G[バージョンチェック]

    F -->|No| ERR4[UnsupportedWeightedRoutingStateException]
    F -->|Yes| G

    G --> H{バージョン一致?}
    H -->|No| ERR5[UnsupportedWeightedRoutingStateException]
    H -->|Yes| I[WeightedRoutingMetadata更新]

    I --> J[クラスタ状態更新]
    J --> K[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 全属性値必須 | 発見済み・フォース設定済みの全属性値に重みを指定 | 常時 |
| BR-02 | 重み0上限 | 半数を超える属性値に重み0を設定不可 | 常時 |
| BR-03 | デコミッション整合性 | デコミッション中の属性値は重み0必須 | デコミッション中 |
| BR-04 | バージョン管理 | 楽観的ロックによる競合防止 | 常時 |
| BR-05 | アウェアネス属性 | 設定済みのアウェアネス属性のみ対象 | 常時 |

### WeightedRouting構造

```
WeightedRouting {
  attributeName: String    // アウェアネス属性名（例: "zone"）
  weights: Map<String, Double>  // 属性値→重みのマップ
}
```

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

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

| 操作 | 対象 | 操作種別 | 概要 |
|-----|------|---------|------|
| 重み設定 | ClusterState.metadata.weightedRoutingMetadata | UPDATE | 重み情報の登録・更新 |
| 重み削除 | ClusterState.metadata.weightedRoutingMetadata | DELETE | 重み情報の削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | ActionRequestValidationException | 無効なアウェアネス属性 | 有効な属性名を指定 |
| 400 | UnsupportedWeightedRoutingStateException | 属性値の重みが未指定 | 全属性値の重みを指定 |
| 400 | UnsupportedWeightedRoutingStateException | 半数以上が重み0 | 重み0の属性値を減らす |
| 400 | UnsupportedWeightedRoutingStateException | デコミッション属性の重みが0でない | 重みを0に設定 |
| 409 | UnsupportedWeightedRoutingStateException | バージョン競合 | 最新バージョンで再試行 |
| 404 | ResourceNotFoundException | 削除対象が存在しない | 設定を確認 |

### リトライ仕様

バージョン競合時はクライアント側で最新バージョンを取得して再試行する必要がある。

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

重み設定はClusterStateUpdateTaskとしてアトミックに実行される。All-or-nothing。

## パフォーマンス要件

- 重み設定はクラスタマネージャノードで実行
- メタデータ更新はミリ秒オーダー
- 全ノードへの伝播は非同期

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

- 重み設定には`cluster:admin/routing/awareness/weights/put`権限が必要
- 誤設定によるトラフィック障害を防ぐため、半数以上の重み0設定を禁止
- バージョン管理による競合防止

## 備考

- V2.4.0以降で利用可能
- ノードデコミッションの前提条件として重み0設定が必要
- FailAwareWeightedRoutingによるフェイルオープン機能あり

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | WeightedRouting.java | `server/src/main/java/org/opensearch/cluster/routing/WeightedRouting.java` | 重みデータ構造 |
| 1-2 | WeightedRoutingMetadata.java | `server/src/main/java/org/opensearch/cluster/metadata/WeightedRoutingMetadata.java` | クラスタメタデータ |

#### Step 2: サービスクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | WeightedRoutingService.java | `server/src/main/java/org/opensearch/cluster/routing/WeightedRoutingService.java` | メインサービスクラス |

**主要処理フロー**:
- **81-128行目**: registerWeightedRoutingMetadata() -- 重み登録処理
- **130-176行目**: deleteWeightedRoutingMetadata() -- 重み削除処理
- **209-252行目**: ensureWeightsSetForAllDiscoveredAndForcedAwarenessValues() -- 属性値検証
- **254-288行目**: ensureDecommissionedAttributeHasZeroWeight() -- デコミッション整合性チェック

#### Step 3: Transport Actionを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TransportAddWeightedRoutingAction.java | `server/src/main/java/org/opensearch/action/admin/cluster/shards/routing/weighted/put/TransportAddWeightedRoutingAction.java` | 重み設定アクション |
| 3-2 | TransportGetWeightedRoutingAction.java | `server/src/main/java/org/opensearch/action/admin/cluster/shards/routing/weighted/get/TransportGetWeightedRoutingAction.java` | 重み取得アクション |
| 3-3 | TransportDeleteWeightedRoutingAction.java | `server/src/main/java/org/opensearch/action/admin/cluster/shards/routing/weighted/delete/TransportDeleteWeightedRoutingAction.java` | 重み削除アクション |

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

```
REST API (PUT /_cluster/routing/awareness/{attribute}/weights)
    |
    +-- TransportAddWeightedRoutingAction
          |
          +-- WeightedRoutingService.registerWeightedRoutingMetadata()
                |
                +-- ensureWeightsSetForAllDiscoveredAndForcedAwarenessValues()
                +-- ensureDecommissionedAttributeHasZeroWeight()
                +-- ensureNoVersionConflict()
                |
                +-- ClusterStateUpdateTask
                      |
                      +-- WeightedRoutingMetadata更新
                      +-- ClusterState.builder().metadata()
```

### データフロー図

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

ClusterPutWeightedRoutingRequest -> TransportAddWeightedRoutingAction -> ClusterStateUpdateResponse
 (attribute,                        |                                    (acknowledged)
  weights,                          +-> WeightedRoutingService
  version)                          |     +-> バリデーション
                                    |     +-> ClusterStateUpdateTask
                                    |
                                    +-> ClusterState更新
                                         (WeightedRoutingMetadata)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| WeightedRouting.java | `server/src/main/java/org/opensearch/cluster/routing/WeightedRouting.java` | ソース | 重みデータ構造 |
| WeightedRoutingMetadata.java | `server/src/main/java/org/opensearch/cluster/metadata/WeightedRoutingMetadata.java` | ソース | メタデータ |
| WeightedRoutingService.java | `server/src/main/java/org/opensearch/cluster/routing/WeightedRoutingService.java` | ソース | メインサービス |
| FailAwareWeightedRouting.java | `server/src/main/java/org/opensearch/cluster/routing/FailAwareWeightedRouting.java` | ソース | フェイルオープン処理 |
| WeightedRoutingStats.java | `server/src/main/java/org/opensearch/cluster/routing/WeightedRoutingStats.java` | ソース | 統計情報 |
| TransportAddWeightedRoutingAction.java | `server/src/main/java/org/opensearch/action/admin/cluster/shards/routing/weighted/put/TransportAddWeightedRoutingAction.java` | ソース | 設定アクション |
| TransportGetWeightedRoutingAction.java | `server/src/main/java/org/opensearch/action/admin/cluster/shards/routing/weighted/get/TransportGetWeightedRoutingAction.java` | ソース | 取得アクション |
| TransportDeleteWeightedRoutingAction.java | `server/src/main/java/org/opensearch/action/admin/cluster/shards/routing/weighted/delete/TransportDeleteWeightedRoutingAction.java` | ソース | 削除アクション |
