# バッチ設計書 17-AbstractAverageUsageTracker (CPU/JVM/IO)

## 概要

本ドキュメントは、CPU・JVM・IO使用率の移動平均を定期的に計算するバッチ処理「AbstractAverageUsageTracker」およびその具体実装（AverageCpuUsageTracker、AverageMemoryUsageTracker、AverageIoUsageTracker）の設計仕様を記載する。

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

AbstractAverageUsageTrackerは、スライディングウィンドウ方式でリソース使用率の移動平均を計算する基底クラスである。具体的な3つのサブクラス（CPU、JVM/メモリ、IO）がそれぞれ独立したバッチとして動作し、ポーリング間隔ごとにリソース使用率を取得して移動平均に記録する。

**業務上の目的・背景**：OpenSearchのリソース監視において、瞬間的な使用率のスパイクではなく、一定期間にわたる平均的なリソース使用状況を把握することが重要である。移動平均を使用することで、一時的な負荷変動を平滑化し、ノードの実質的な負荷状態を正確に反映した情報を提供できる。これらの統計はResourceUsageCollectorService（No.16）を通じてコーディネータノードに伝達され、検索リクエストのルーティングやバックプレッシャー制御に活用される。

**バッチの実行タイミング**：各トラッカーは独立したポーリング間隔で実行される。
- CPU: `node.resource.tracker.global_cpu_usage.polling_interval`（デフォルト500ms）
- JVM/メモリ: `node.resource.tracker.global_jvmmp.polling_interval`（デフォルト500ms）
- IO: `node.resource.tracker.global_io_usage.polling_interval`（デフォルト5000ms）

**主要な処理内容**：
1. 各サブクラスのgetUsage()メソッドでリソース使用率を取得
2. recordUsage()でMovingAverageオブジェクトにデータポイントを記録
3. ウィンドウサイズ分のデータが蓄積されるとisReady()がtrueを返す

**前後の処理との関連**：NodeResourceUsageTrackerが3つのトラッカー（CPU、メモリ、IO）をまとめて管理する。各トラッカーの移動平均はNodeResourceUsageTracker経由でResourceUsageCollectorService（No.16）に提供される。ウィンドウサイズはクラスタ設定で動的に変更可能。

**影響範囲**：各ノードのリソース使用統計の精度に影響。移動平均ウィンドウの設定により、統計の応答性と安定性のバランスが変化する。

## バッチ種別

リソース監視 / 統計計算

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | CPU/JVM: 500ms間隔、IO: 5000ms間隔（設定可能） |
| 実行時刻 | ノード起動後、ポーリング間隔ごとに繰り返し実行 |
| 実行曜日 | 該当なし（常時） |
| 実行日 | 該当なし（常時） |
| トリガー | ThreadPool.scheduleWithFixedDelay（Names.GENERIC） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| NodeResourceUsageTrackerがstart済み | doStart()で各トラッカーが開始される |
| IO: Linux環境であること | AverageIoUsageTrackerはLinux環境でのみスケジュールされる |
| IO: FsServiceが利用可能であること | IOスタッツの取得にFsServiceが必要 |

### 実行可否判定

AbstractAverageUsageTrackerのdoStart()は無条件にスケジュールを開始する。ただし、AverageIoUsageTrackerはdoStart()をオーバーライドしており、Constants.LINUX==trueの場合にのみスケジュールを行う。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| node.resource.tracker.global_cpu_usage.polling_interval | TimeValue | No | 500ms | CPUポーリング間隔 |
| node.resource.tracker.global_cpu_usage.window_duration | TimeValue | No | 30s | CPU移動平均ウィンドウ |
| node.resource.tracker.global_jvmmp.polling_interval | TimeValue | No | 500ms | JVMメモリポーリング間隔 |
| node.resource.tracker.global_jvmmp.window_duration | TimeValue | No | 30s | JVMメモリ移動平均ウィンドウ |
| node.resource.tracker.global_io_usage.polling_interval | TimeValue | No | 5000ms | IOポーリング間隔 |
| node.resource.tracker.global_io_usage.window_duration | TimeValue | No | 120s | IO移動平均ウィンドウ |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| ProcessProbe.getInstance().getProcessCpuPercent() | long | プロセスCPU使用率（%） |
| JvmStats経由のメモリ使用率 | long | JVMメモリ使用率 |
| FsService.stats().getIoStats() | DeviceStats[] | デバイスごとのIO統計 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| MovingAverage | インメモリ | 移動平均オブジェクト（getAverage()で取得） |
| IoUsageStats | インメモリ | IO使用統計（AverageIoUsageTrackerのみ） |

### 出力ファイル仕様

ファイル出力はなし。

## 処理フロー

### 処理シーケンス

```
1. スケジュールされたラムダが実行
   └─ getUsage()で現在の使用率を取得
2. recordUsage(usage)で移動平均に記録
   └─ MovingAverage.record()にデータポイントを追加
3. [IO限定] updateIoUsageStats()
   └─ isReady()がtrueの場合、IoUsageStatsのioUtilisationPercentを更新

--- AverageCpuUsageTracker ---
getUsage(): ProcessProbe.getInstance().getProcessCpuPercent()を返す

--- AverageIoUsageTracker ---
getUsage():
  1. FsService.stats()のバリデーション
  2. デバイスごとのIOタイム差分を計算
  3. IO使用率 = (IOタイム差分 * 100) / 経過時間
  4. 全デバイスの最大値を返す
```

### フローチャート

```mermaid
flowchart TD
    A[スケジュール実行] --> B[getUsage 呼び出し]
    B --> C[リソース使用率を取得]
    C --> D[recordUsage: MovingAverageに記録]
    D --> E{IOトラッカー?}
    E -->|Yes| F[updateIoUsageStats]
    E -->|No| G[処理完了]
    F --> G
```

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

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

本バッチはデータベース操作を行わない。インメモリのMovingAverageオブジェクトの操作のみを行う。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| なし | ValidationException | IOトラッカー: FsServiceのIOStats/DeviceStatsが未初期化 | ValidationExceptionがスローされる |
| なし | Exception | getUsage()内の例外 | scheduleWithFixedDelayにより次回実行で再試行 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 明示的なリトライなし（定期実行により自動再試行） |
| リトライ間隔 | 各トラッカーのポーリング間隔 |
| リトライ対象エラー | すべてのException |

### 障害時対応

統計が取得できない場合、isReady()がfalseのままとなり、ResourceUsageCollectorServiceでの収集がスキップされる。FsServiceの初期化遅延の場合は、サービス準備完了後に自動的にデータ収集が開始される。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし（AtomicReferenceでMovingAverageを管理） |
| コミットタイミング | 即時 |
| ロールバック条件 | 該当なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 各ポーリングで1データポイント |
| 目標処理時間 | マイクロ秒単位（プローブ読み取りのみ） |
| メモリ使用量上限 | MovingAverageのウィンドウサイズ x long型（8バイト） |

## 排他制御

MovingAverageオブジェクトはAtomicReference<MovingAverage>で管理されており、setWindowSize()時に新しいMovingAverageインスタンスに原子的に置換される。ただし、getUsage()とrecordUsage()の間に別スレッドがsetWindowSize()を呼ぶと、古いMovingAverageインスタンスにrecordされる可能性がある（許容される挙動）。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| デバッグログ | ウィンドウサイズ更新時 | "updated window size: {size}" |
| デバッグログ | CPU使用率取得時 | "Recording cpu usage: {usage}%" |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| CPU使用率移動平均 | アプリケーション依存 | ResourceUsageCollectorService経由 |
| IO使用率移動平均 | アプリケーション依存 | ResourceUsageCollectorService経由 |
| メモリ使用率移動平均 | アプリケーション依存 | ResourceUsageCollectorService経由 |

## 備考

- 基底クラス実装ファイル: `server/src/main/java/org/opensearch/node/resource/tracker/AbstractAverageUsageTracker.java`
- CPU実装: `server/src/main/java/org/opensearch/node/resource/tracker/AverageCpuUsageTracker.java`
- IO実装: `server/src/main/java/org/opensearch/node/resource/tracker/AverageIoUsageTracker.java`
- メモリ実装: AverageMemoryUsageTrackerクラス（同パッケージ）
- 設定ファイル: `server/src/main/java/org/opensearch/node/resource/tracker/ResourceTrackerSettings.java`
- AbstractAverageUsageTrackerはAbstractLifecycleComponentを継承している
- ウィンドウサイズ = windowDuration / pollingInterval で計算される
- window_durationはクラスタ設定で動的に変更可能（Property.Dynamic）、polling_intervalはNodeScope固定
- AverageIoUsageTrackerはLinux環境（Constants.LINUX）でのみ動作する
- IOの使用率は全接続デバイスの最大値を採用する
