# 機能設計書 125-インデックススケーリング

## 概要

本ドキュメントは、OpenSearchにおけるインデックスの検索レプリカを動的にスケーリングする機能の設計を記載する。

### 本機能の処理概要

本機能は、インデックスを通常モードと検索専用（search-only）モードの間で切り替え、検索レプリカを動的にスケーリングする機能である。

**業務上の目的・背景**：時系列データや読み取りが主体のインデックスでは、書き込み機能を維持するためのプライマリシャードが不要になる場面がある。検索専用モードに切り替えることで、書き込み用シャードを削除しリソースを節約しつつ、検索レプリカのみで検索サービスを維持できる。スケールアップ時には通常モードに復帰し、書き込みを再開できる。

**機能の利用シーン**：ホットからウォームへのティア移行時、書き込みが完了したインデックスのリソース最適化、コスト削減のための検索専用モード移行、再度書き込みが必要になった場合のスケールアップ時に利用される。

**主要な処理内容**：
1. スケールダウン: 一時書き込みブロック追加 -> シャード同期 -> 検索専用モード確定
2. スケールアップ: ルーティングテーブル再構築 -> 検索専用ブロック解除 -> シャードアロケーション

**関連システム・外部連携**：AllocationServiceによるシャード再配置。リモートストアとの同期（shard.sync(), shard.waitForRemoteStoreSync()）。

**権限による制御**：METADATA_WRITEレベルのクラスタブロックチェック。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はAPIとして提供され、専用の画面は定義されていない |

## 機能種別

クラスタ状態更新（インデックスモード切り替え）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| index | String | Yes | 対象インデックス名 | 空でないこと |
| scaleDown | boolean | Yes | true: 検索専用モードへ縮小, false: 通常モードへ復帰 | - |
| timeout | TimeValue | No | ACKタイムアウト | - |

### 入力データソース

REST APIリクエスト

## 出力仕様

### 出力データ

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

### 出力先

REST APIレスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
【スケールダウン】
1. バリデーション
   └─ ScaleIndexOperationValidator.validateScalePrerequisites()
2. 一時書き込みブロック追加
   └─ AddBlockClusterStateUpdateTask実行
3. シャード同期
   └─ 各プライマリシャードへsyncリクエスト送信
   └─ shard.sync() -> shard.flush() -> shard.waitForRemoteStoreSync()
4. 検索専用モード確定
   └─ FinalizeScaleDownTaskでメタデータ更新・永続ブロック追加

【スケールアップ】
1. バリデーション
   └─ 検索専用モードであることを確認
2. ルーティングテーブル再構築
   └─ プライマリ＋レプリカシャードの追加
3. 検索専用ブロック解除・設定更新
   └─ INDEX_SEARCH_ONLY_BLOCK_ID の削除
4. シャードアロケーション
   └─ AllocationService.reroute()
```

### フローチャート

```mermaid
flowchart TD
    A[ScaleIndexRequest受信] --> B{スケールダウン?}
    B -->|Yes| C[一時書き込みブロック追加]
    C --> D[プライマリシャード同期]
    D --> E[sync + flush + remoteStoreSync]
    E --> F[検索専用モード確定]
    F --> G[AcknowledgedResponse]
    B -->|No| H[検索専用モード確認]
    H --> I[ルーティングテーブル再構築]
    I --> J[検索専用ブロック解除]
    J --> K[AllocationService.reroute]
    K --> G
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 前提条件チェック | スケールダウン前にインデックスが通常モードであることを検証 | スケールダウン時 |
| BR-002 | プライマリシャード同期 | スケールダウン時、全プライマリシャードの同期・フラッシュ・リモートストア同期を完了させる | スケールダウン時 |
| BR-003 | 同期タイムアウト | シャード同期のオペレーション許可取得に30秒のタイムアウト | スケールダウン時 |
| BR-004 | URGENTプライオリティ | クラスタ状態更新タスクはURGENTプライオリティで実行 | スケールダウン時 |

### 計算ロジック

特になし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| スケールダウン | クラスタ状態 | UPDATE | インデックスメタデータ、ルーティングテーブル、ブロックの更新 |
| スケールアップ | クラスタ状態 | UPDATE | ルーティングテーブル再構築、ブロック解除、設定変更 |

### テーブル別操作詳細

クラスタ状態メタデータのインデックス設定とルーティングテーブルが更新される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ActionRequestValidationException | バリデーション | インデックス名未指定 | リクエスト修正 |
| IllegalStateException | 状態不正 | インデックスが見つからない、レプリカシャードの縮小試行 | インデックス名確認 |
| IOException | 同期失敗 | シャードのsync/flush操作中のI/Oエラー | リトライ |
| ClusterBlockException | ブロック例外 | METADATA_WRITEブロック存在時 | ブロック解除後再試行 |

### リトライ仕様

失敗時はActionListenerで通知される。自動リトライは行わない。

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

複数のClusterStateUpdateTaskによる段階的なクラスタ状態更新。各段階の失敗時はリスナーで通知。

## パフォーマンス要件

MANAGEMENTスレッドプールで実行。シャード同期にはI/O操作を伴うため、大規模インデックスでは時間を要する。

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

METADATA_WRITEレベルのクラスタブロックチェックが行われる。

## 備考

本機能はsearch-onlyスケーリング機能として新規に追加されたもの。ScaleIndexClusterStateBuilder、ScaleIndexOperationValidator、ScaleIndexShardSyncManagerが処理を分担する。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ScaleIndexRequest.java | `server/src/main/java/org/opensearch/action/admin/indices/scale/searchonly/ScaleIndexRequest.java` | index名とscaleDown フラグを保持するリクエスト |
| 1-2 | ScaleIndexNodeRequest.java | 同上 | ノード間同期リクエスト（index名とシャードID一覧） |
| 1-3 | ScaleIndexNodeResponse.java | 同上 | ノード同期レスポンス |
| 1-4 | ScaleIndexShardResponse.java | 同上 | シャード単位の同期結果（syncNeeded, uncommittedOps） |

**読解のコツ**: ScaleIndexRequestのscaleDown=trueが検索専用モードへの縮小、falseが通常モードへの復帰を表す。

#### Step 2: トランスポートアクションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | TransportScaleIndexAction.java | `server/src/main/java/org/opensearch/action/admin/indices/scale/searchonly/TransportScaleIndexAction.java` | メイン処理。スケールダウン/アップの分岐、3つのClusterStateUpdateTask |

**主要処理フロー**:
- **167-179行目**: clusterManagerOperation()でスケールダウン/アップを分岐
- **184-191行目**: submitScaleDownTask()で一時ブロック追加タスク送信
- **280-302行目**: syncSingleShard()でsync, flush, waitForRemoteStoreSync実行
- **307-318行目**: submitScaleUpTask()でルーティングテーブル再構築

#### Step 3: 補助クラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ScaleIndexClusterStateBuilder.java | 同上 | クラスタ状態構築ロジック |
| 3-2 | ScaleIndexOperationValidator.java | 同上 | スケーリング前提条件のバリデーション |
| 3-3 | ScaleIndexShardSyncManager.java | 同上 | ノード間シャード同期のコーディネーション |

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

```
TransportScaleIndexAction
    |
    +-- [Scale Down]
    |   +-- AddBlockClusterStateUpdateTask
    |   |       +-- ScaleIndexOperationValidator.validateScalePrerequisites()
    |   |       +-- ScaleIndexClusterStateBuilder.buildScaleDownState()
    |   +-- ScaleIndexShardSyncManager.sendShardSyncRequests()
    |   |       +-- handleShardSyncRequest() [各ノード]
    |   |               +-- syncSingleShard()
    |   |                       +-- shard.sync()
    |   |                       +-- shard.flush()
    |   |                       +-- shard.waitForRemoteStoreSync()
    |   +-- FinalizeScaleDownTask
    |           +-- ScaleIndexClusterStateBuilder.buildFinalScaleDownState()
    |
    +-- [Scale Up]
        +-- ScaleUpClusterStateUpdateTask
                +-- ScaleIndexClusterStateBuilder.buildScaleUpRoutingTable()
                +-- AllocationService.reroute()
```

### データフロー図

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

ScaleIndexRequest -->  TransportScaleIndexAction  -->  AcknowledgedResponse
(index, scaleDown)     |
                       +-> ClusterState更新（一時ブロック）
                       +-> シャード同期（sync/flush/remoteSync）
                       +-> ClusterState更新（確定）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ScaleIndexAction.java | `server/src/main/java/org/opensearch/action/admin/indices/scale/searchonly/` | ソース | アクション定義 |
| ScaleIndexRequest.java | 同上 | ソース | リクエスト |
| ScaleIndexResponse.java | 同上 | ソース | レスポンス |
| TransportScaleIndexAction.java | 同上 | ソース | メインアクション実装 |
| ScaleIndexClusterStateBuilder.java | 同上 | ソース | クラスタ状態構築 |
| ScaleIndexOperationValidator.java | 同上 | ソース | バリデーション |
| ScaleIndexShardSyncManager.java | 同上 | ソース | シャード同期管理 |
| ScaleIndexNodeRequest.java | 同上 | ソース | ノード間リクエスト |
| ScaleIndexNodeResponse.java | 同上 | ソース | ノード間レスポンス |
| ScaleIndexShardResponse.java | 同上 | ソース | シャード同期結果 |
