# バッチ設計書 10-AutoForceMergeManager (AsyncForceMergeTask)

## 概要

本ドキュメントは、OpenSearchのAutoForceMergeManagerにおけるプライマリシャードの自動フォースマージを管理するバッチタスクの設計を記載する。

### 本バッチの処理概要

AutoForceMergeManager（AsyncForceMergeTask）は、トランスログの経過時間やシステムリソース状態に基づいて、プライマリシャードに対する自動的なフォースマージを定期的にトリガーするバッチタスクである。

**業務上の目的・背景**：OpenSearchのインデックスは時間の経過とともに多数のセグメントが蓄積され、検索パフォーマンスの低下やディスク使用量の増大を引き起こす。フォースマージにより複数のセグメントを結合してセグメント数を削減できるが、リソース集約的な操作であるため、ノードのCPU・メモリ・ディスク使用率を考慮して適切なタイミングで実行する必要がある。本バッチはこの判断と実行を自動化する。特にリモートストア環境のウォームノードを持つクラスタにおいて、ホットノード上のデータを自動的に最適化するために設計されている。

**バッチの実行タイミング**：`node.auto_force_merge.scheduler.interval`（デフォルト30分）の間隔で定期実行される。AsyncForceMergeTaskとしてAbstractAsyncTaskを使用する。

**主要な処理内容**：
1. 構成バリデーション（リモートストア有効、データノード、ウォームノード存在確認）
2. ノードバリデーション（CPU・JVM・ディスク使用率、フォースマージスレッド空き確認）
3. 対象シャードの選定（トランスログ経過時間、セグメント数閾値、ソート）
4. シャードごとにフォースマージの実行（非同期、FORCE_MERGEスレッドプール）
5. シャード間の遅延挿入（過負荷防止）

**前後の処理との関連**：本タスクはインデクシング処理の後続として、書き込みが落ち着いたシャードに対してセグメント最適化を行う。リフレッシュ（No.2）やフラッシュ処理の後に蓄積されたセグメントが対象となる。

**影響範囲**：対象プライマリシャードのLuceneセグメント構造に大きな影響を与える。フォースマージはCPU・I/O集約的な操作であり、ノード全体のパフォーマンスに影響しうる。

## バッチ種別

データ最適化処理（セグメントの統合・フォースマージ）

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 定期実行（デフォルト30分間隔） |
| 実行時刻 | ノードのライフサイクルに依存（常時） |
| 実行曜日 | 該当なし（常時稼働） |
| 実行日 | 該当なし（常時稼働） |
| トリガー | タイマーベースの定期スケジュール（AbstractAsyncTask） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| 自動フォースマージ有効 | `cluster.auto_force_merge.enabled`がtrueであること |
| リモートストア有効 | クラスタ設定でリモートクラスタ状態が有効であること |
| データノード（非ウォーム） | ノードがデータノードかつウォームノードでないこと |
| ウォームノード存在 | クラスタにウォームノードが存在すること |
| CPU閾値内 | CPU使用率が`node.auto_force_merge.cpu.threshold`（デフォルト75%）未満 |
| JVM閾値内 | JVMメモリ使用率が`node.auto_force_merge.jvm.threshold`（デフォルト75%）未満 |
| ディスク閾値内 | ディスク使用率が`node.auto_force_merge.disk.threshold`（デフォルト85%）未満 |
| フォースマージスレッド空き | FORCE_MERGEスレッドプールのキューが0 |

### 実行可否判定

3段階のバリデーションが行われる:
1. **ConfigurationValidator**: 機能有効化、リモートストア有効、データノード判定
2. **NodeValidator**: CPU・JVM・ディスク使用率の閾値チェック、フォースマージスレッド空き確認
3. **ShardValidator**: シャード状態（STARTED）、インデックスの自動フォースマージ有効、トランスログ経過時間、セグメント数閾値

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| cluster.auto_force_merge.enabled | Boolean | No | false | 自動フォースマージの有効/無効 |
| node.auto_force_merge.scheduler.interval | TimeValue | No | 30m | スケジューラの実行間隔（1s-24h） |
| node.auto_force_merge.segment.count | Integer | No | 1 | 目標セグメント数（最小1） |
| node.auto_force_merge.merge_delay | TimeValue | No | 15s | シャード間の遅延（1s-60s） |
| node.auto_force_merge.translog.age | TimeValue | No | 30m | トランスログ経過時間閾値（1s-24h） |
| node.auto_force_merge.cpu.threshold | Double | No | 75.0 | CPU使用率閾値（10-100%） |
| node.auto_force_merge.disk.threshold | Double | No | 85.0 | ディスク使用率閾値（10-100%） |
| node.auto_force_merge.jvm.threshold | Double | No | 75.0 | JVMメモリ使用率閾値（10-100%） |
| node.auto_force_merge.threads.concurrency_multiplier | Integer | No | 2 | 並行マージ数の乗数（2-5） |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| IndicesService | インメモリ | ノード上の全インデックスおよびシャード |
| OsService | インメモリ | OS統計情報（CPU使用率） |
| JvmService | インメモリ | JVM統計情報（メモリ使用率） |
| FsService | インメモリ | ファイルシステム統計情報（ディスク使用率） |
| TranslogStats | インメモリ | トランスログの統計情報（経過時間） |
| SegmentsStats | インメモリ | セグメントの統計情報（セグメント数） |
| ResourceTrackers | インメモリ | CPU/JVMの1分/5分移動平均 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| Luceneセグメント | ディスクファイル | マージにより統合されたセグメントファイル |
| メトリクス | インメモリ | フォースマージの実行統計 |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | Luceneセグメントファイル（マージ後） |
| 出力先 | 各シャードのインデックスディレクトリ |
| 文字コード | バイナリ形式 |
| 区切り文字 | 該当なし |

## 処理フロー

### 処理シーケンス

```
1. タイマーによる定期起動
   └─ AbstractAsyncTaskにより30分間隔で起動
2. 構成バリデーション
   └─ ConfigurationValidator: 機能有効、リモートストア、ノードタイプ、ウォームノード確認
3. ノードバリデーション
   └─ NodeValidator: CPU/JVM/ディスク使用率、スレッド空き確認
4. 対象シャード選定
   └─ 全シャードをフィルタ・ソート（システムインデックス除外、プライマリのみ、トランスログ経過時間順）
5. シャードごとのフォースマージ実行
   └─ CompletableFuture.runAsync()でFORCE_MERGEスレッドプールに投入
6. シャード間遅延
   └─ Thread.sleep(forcemergeDelay)で過負荷防止
7. メトリクス記録
   └─ 実行時間、セグメント数、シャードサイズ等を記録
```

### フローチャート

```mermaid
flowchart TD
    A[タイマー起動] --> B{構成バリデーション OK?}
    B -->|No| Z[スキップ・再スケジュール]
    B -->|Yes| C{ウォームノード存在?}
    C -->|No| Z
    C -->|Yes| D{ノードバリデーション OK?}
    D -->|No| Z
    D -->|Yes| E[対象シャード選定・ソート]
    E --> F{次のシャードあり?}
    F -->|No| Z
    F -->|Yes| G{残り実行回数 > 0?}
    G -->|No| Z
    G -->|Yes| H{ノード条件OK?}
    H -->|No| Z
    H -->|Yes| I[非同期フォースマージ実行]
    I --> J[シャード間遅延]
    J --> F
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フォースマージ | Luceneセグメント | READ/WRITE/DELETE | 複数セグメントの読み込み・統合・古いセグメントの削除 |

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

#### Luceneセグメント

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| MERGE | 複数セグメント -> 統合セグメント | maxNumSegments=segmentCount（デフォルト1）に統合 | CPU/I/O集約的な操作 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Exception | フォースマージ実行時のエラー | エラーログ出力、mergesFailedメトリクス記録、次のシャードに進む |
| - | InterruptedException | シャード間遅延中の割り込み | スレッド割り込みフラグを設定、ループを終了 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 明示的なリトライなし（次回スケジュール実行で再試行） |
| リトライ間隔 | scheduler.interval（デフォルト30分） |
| リトライ対象エラー | 次回実行時に自動的に再試行 |

### 障害時対応

フォースマージに失敗した場合、エラーログが出力され`mergesFailed`メトリクスが記録される。対象シャードは次回スケジュール実行時に再度対象となる。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | シャード単位（各シャードのフォースマージは独立） |
| コミットタイミング | フォースマージ完了時 |
| ロールバック条件 | フォースマージ失敗時は元のセグメント構造が維持される |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | max(1, allocatedProcessors/8) * concurrencyMultiplier シャード |
| 目標処理時間 | scheduler.interval内に完了すること（ただしフォースマージ自体は非同期） |
| メモリ使用量上限 | JVM閾値（デフォルト75%）を超えない範囲 |

## 排他制御

- ノード単位でAutoForceMergeManagerは1つのみ存在する
- `mergingShards` Setにより、同一シャードの同時フォースマージを防止する
- `flushOrRollRunning`（IndexShard側）との競合は考慮されない（フォースマージはFORCE_MERGEスレッドプールで非同期実行）
- `maxConcurrentForceMerges`により同時実行数を制限する

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| デバッグログ | バリデーション失敗時 | 各バリデーション失敗理由 |
| 情報ログ | フォースマージトリガー時 | "Successfully triggered force merge for shard {shardId}" |
| デバッグログ | フォースマージ完了時 | "Merging is completed successfully for the shard {shardId}" |
| エラーログ | フォースマージ失敗時 | "Error during force merge for shard {shardId}" + 例外情報 |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| schedulerExecutionTime | スケジューラの実行時間 | OpenSearchメトリクス（ヒストグラム） |
| mergesTriggered | トリガーされたマージ数 | OpenSearchメトリクス（カウンタ） |
| mergesFailed | 失敗したマージ数 | OpenSearchメトリクス（カウンタ） |
| segmentCount | マージ前のセグメント数 | OpenSearchメトリクス（カウンタ） |
| shardSize | シャードサイズ | OpenSearchメトリクス（カウンタ） |
| shardMergeLatency | シャードのマージレイテンシ | OpenSearchメトリクス（ヒストグラム） |
| skipsFromConfigValidator | 構成バリデーションによるスキップ数 | OpenSearchメトリクス（カウンタ） |
| skipsFromNodeValidator | ノードバリデーションによるスキップ数 | OpenSearchメトリクス（カウンタ） |

## 備考

- スケジューラ自体はGENERICスレッドプールで実行され、実際のフォースマージはFORCE_MERGEスレッドプールで非同期実行される
- AbstractLifecycleComponentを継承しており、Node起動時にstart、停止時にstopが呼ばれる
- システムインデックス（"."で始まるインデックス名）は対象外
- シャードの選定はトランスログの経過時間（earliestLastModifiedAge）昇順でソートされる
- CPU/JVMの移動平均（1分・5分）とリアルタイム値の両方がチェックされる
- ResourceTrackerProviderにより、リソース監視用の移動平均トラッカーが提供される
- 全設定はDynamic/NodeScopeでクラスタ設定の動的更新に対応する
- ソースコード:
  - `server/src/main/java/org/opensearch/index/autoforcemerge/AutoForceMergeManager.java`
  - `server/src/main/java/org/opensearch/index/autoforcemerge/ForceMergeManagerSettings.java`
