# バッチ設計書 28-SearchBackpressureService

## 概要

本ドキュメントは、OpenSearchのSearchBackpressureServiceが提供する検索タスクのバックプレッシャー評価・制御バッチ処理の設計を記述する。このバッチはノードのリソース逼迫時に検索タスクのリソース使用状況を定期的に評価し、過剰消費タスクをキャンセルする。

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

SearchBackpressureServiceは、AbstractLifecycleComponentとして実装されたサービスであり、SearchTaskおよびSearchShardTaskのCPU使用時間、ヒープ使用量、経過時間を監視する。ノードがリソース逼迫状態にある場合、リソース閾値を超過した検索タスクを特定し、トークンバケットアルゴリズムによるレート制限の下でタスクをキャンセルする。

**業務上の目的・背景**：大規模な検索クエリやアグリゲーション処理は、CPU・メモリ・時間リソースを大量に消費する。これらがノード全体のリソースを圧迫すると、他のリクエストの処理に影響が出る。SearchBackpressureServiceは、ノード逼迫時にリソース消費の大きい検索タスクを自動的にキャンセルすることで、ノードの安定性と応答性を維持する。monitor_onlyモードでは実際のキャンセルは行わずログ出力のみを行い、enforcedモードで実際のキャンセルを実行する。

**バッチの実行タイミング**：search_backpressure.interval_millis設定（デフォルト1000ms）の間隔で定期実行される。

**主要な処理内容**：
1. SearchBackpressureModeがDISABLEDでないことを確認する
2. NodeDuressTrackersでノードのリソース逼迫状態（CPU、メモリ）を評価する
3. SearchTaskとSearchShardTaskのリソース統計をリフレッシュする
4. ヒープ使用量が検索トラフィックによるものかを判定する
5. CPU使用量トラッカー、ヒープ使用量トラッカー、経過時間トラッカーでキャンセル対象を特定する
6. 重複するキャンセル対象をマージし、トークンバケットによるレート・比率制限の下でキャンセルを実行する

**前後の処理との関連**：TaskResourceTrackingServiceがタスクのリソース使用量を追跡する。WorkloadGroupServiceのshouldSBPHandle()により、ワークロード管理が処理するタスクとの分担が行われる。タスク完了時にはonTaskCompleted()でトラッカーの更新と完了カウントの記録が行われる。

**影響範囲**：ノード上の全SearchTaskおよびSearchShardTaskに影響する。enforcedモードではリソース超過タスクが強制キャンセルされる。

## バッチ種別

リソース監視・バックプレッシャー制御

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | search_backpressure.interval_millis（デフォルト1000ms） |
| 実行時刻 | サービス起動後から継続的に実行 |
| 実行曜日 | 該当なし（常時） |
| 実行日 | 該当なし（常時） |
| トリガー | ThreadPool.scheduleWithFixedDelayによる定期実行 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| search_backpressure.mode | DISABLEDでないこと（monitor_only または enforced） |
| ノード逼迫状態 | NodeDuressTrackersがisNodeInDuress() == trueであること |

### 実行可否判定

doRun()内で、modeがDISABLEDの場合は即座にreturnする。次にnodeDuressTrackers.isNodeInDuress()がfalseの場合もreturnする。これにより、ノードが正常な場合は処理をスキップし、オーバーヘッドを最小化する。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| search_backpressure.mode | SearchBackpressureMode | No | monitor_only | 動作モード（disabled/monitor_only/enforced） |
| search_backpressure.interval_millis | long | No | 1000 | 実行間隔（ミリ秒） |
| search_backpressure.cancellation_ratio | double | No | 0.1 | 成功タスクに対するキャンセル比率 |
| search_backpressure.cancellation_rate | double | No | 0.003 | 時間あたりのキャンセルレート |
| search_backpressure.cancellation_burst | double | No | 10.0 | レート制限前の最大キャンセル数 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| TaskResourceTrackingService | Java API | タスクのリソース使用量 |
| NodeDuressTrackers | Java API | ノードのCPU・メモリ逼迫状態 |
| ProcessProbe | Java API | プロセスCPU使用率 |
| JvmStats | Java API | JVMヒープ使用率 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| TaskCancellation | Java API | タスクキャンセル実行（enforcedモード） |
| SearchBackpressureStats | Java Object | ノード統計API向けの統計情報 |
| SearchBackpressureState | Java Object | キャンセル数、完了数、制限到達数の状態 |

### 出力ファイル仕様

ファイル出力はなし。ノード統計APIを通じて公開される。

## 処理フロー

### 処理シーケンス

```
1. モードチェック
   └─ DISABLEDの場合はスキップ
2. ノード逼迫状態チェック
   └─ NodeDuressTrackersでCPU/メモリの逼迫判定
   └─ 逼迫していない場合はスキップ
3. SearchTask/SearchShardTaskのリスト取得
   └─ WorkloadGroupServiceのshouldSBPHandle()でフィルタリング
4. ヒープ使用量判定
   └─ 検索タスクのヒープ使用が支配的かチェック
5. タスクリソース統計のリフレッシュ
   └─ taskResourceTrackingService.refreshResourceStats()
6. 各トラッカーによるキャンセル候補の収集
   └─ CPU使用量トラッカー（CPUが逼迫時のみ）
   └─ ヒープ使用量トラッカー（メモリが逼迫時のみ）
   └─ 経過時間トラッカー（常時）
7. キャンセル候補のマージ（重複除去）
8. SBP状態更新コールバックの追加
9. キャンセル適格性チェック
10. enforcedモードの場合、トークンバケットによるレート制限
    └─ rateLimiterとratioLimiterの両方を確認
11. タスクキャンセル実行
    └─ taskCancellation.cancelTaskAndDescendants()
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B{mode == DISABLED?}
    B -->|Yes| C[スキップ]
    B -->|No| D{ノード逼迫状態?}
    D -->|No| C
    D -->|Yes| E[SearchTask/SearchShardTask取得]
    E --> F[ヒープ支配判定]
    F --> G[リソース統計リフレッシュ]
    G --> H[各トラッカーでキャンセル候補収集]
    H --> I[キャンセル候補マージ]
    I --> J[適格性フィルタリング]
    J --> K{mode == ENFORCED?}
    K -->|No| L[WARNログ出力のみ]
    K -->|Yes| M[トークンバケット制限チェック]
    M --> N{レート制限到達?}
    N -->|Yes| O[制限到達カウント増加]
    N -->|No| P[タスクキャンセル実行]
    P --> Q[バッチ終了]
    O --> Q
    L --> Q
    C --> Q
```

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

本バッチはデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IllegalArgumentException | タスクがSearchTask/SearchShardTask以外の場合 | 例外スロー |
| - | Exception | doRun()内の例外 | DEBUGログ出力してスキップ |
| - | Exception | タスク完了時のトラッカー更新エラー | ExceptionsHelper.maybeThrowRuntimeAndSuppress |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（次回スケジュールで再実行） |
| リトライ間隔 | search_backpressure.interval_millis（デフォルト1000ms） |
| リトライ対象エラー | 全てのエラー（次回実行で自動リトライ） |

### 障害時対応

例外発生時はDEBUGログが出力され、次回スケジュールで再試行される。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし |
| コミットタイミング | 該当なし |
| ロールバック条件 | 該当なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 実行中の検索タスク数に依存 |
| 目標処理時間 | 実行間隔（1秒）内に完了すること |
| メモリ使用量上限 | タスクリスト・キャンセルリストの管理程度 |

## 排他制御

トークンバケット（rateLimiterとratioLimiter）がキャンセルのレート制限を提供する。rateLimiterは時間あたりのキャンセル数を制限し、ratioLimiterは成功タスク数に対するキャンセル比率を制限する。両方のトークンが枯渇した場合、キャンセルが中断される。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| WARNログ | キャンセル候補検出時 | モード名、タスクID、リソース消費理由 |
| DEBUGログ | レート制限到達時 | "task cancellation limit reached" |
| DEBUGログ | バッチ処理の例外発生時 | "failure in search search backpressure" |
| WARNログ | ヒープサイズ判定不能時 | "heap size couldn't be determined" |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| タスクキャンセル数 | ノード統計APIで確認 | 運用チーム |
| レート制限到達数 | ノード統計APIで確認 | 運用チーム |
| タスク完了数 | ノード統計APIで確認 | 運用チーム |

## 備考

- 3つのリソーストラッカー（CPU、ヒープ、経過時間）が独立してキャンセル候補を評価する
- CPUトラッカーはCPU逼迫時のみ、ヒープトラッカーはメモリ逼迫時のみ適用される。経過時間トラッカーは常時適用される
- ヒープトラッカーの適用にはisHeapTrackingSupported()がtrueである必要がある
- monitor_onlyモードではログ出力のみで実際のキャンセルは行われない
- SearchBackpressureSettingsの一部はDeprecatedとなり、SearchShardTaskSettingsに移行している
- GENERICスレッドプールで実行される
