# 機能設計書 90-GPUリソース

## 概要

本ドキュメントは、Apache FlinkのGPU外部リソース管理（flink-external-resource-gpu）の機能設計書である。GPUデバイスを検出し、Flinkジョブにリソース情報を提供する。

### 本機能の処理概要

flink-external-resource-gpuモジュールは、ExternalResourceDriverインターフェースを実装し、システム上のGPUリソースを検出・管理する。ユーザー定義のディスカバリスクリプトを実行し、利用可能なGPUインデックスを取得する。

**業務上の目的・背景**：機械学習やディープラーニングワークロードでは、GPUを活用した高速処理が必要となる。FlinkでGPUリソースを管理することで、GPUを使用するオペレーターに適切なリソース割り当てが可能となる。

**機能の利用シーン**：(1)機械学習推論ジョブの実行、(2)GPUアクセラレーションを必要とするデータ処理、(3)NVIDIA GPU環境でのFlinkクラスタ運用

**主要な処理内容**：
1. **GPUDriver**: GPUリソース検出ドライバー
2. **GPUDriverFactory**: GPUDriver生成ファクトリ
3. **GPUInfo**: GPU情報保持クラス
4. **GPUDriverOptions**: 設定オプション定義

**関連システム・外部連携**：ディスカバリスクリプト（nvidia-gpu-discovery.sh等）

**権限による制御**：スクリプト実行権限

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ランタイムリソース管理のため関連画面なし |

## 機能種別

リソース管理 / 外部リソースドライバー

## 入力仕様

### 入力パラメータ（Configuration）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| discovery-script.path | String | Yes | ディスカバリスクリプトパス | 実行可能ファイル |
| discovery-script.args | String | No | スクリプト引数 | - |

### 入力データソース

- Flinkクラスタ設定（flink-conf.yaml）
- ディスカバリスクリプト出力（カンマ区切りGPUインデックス）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| GPUInfo Set | Set<GPUInfo> | 検出されたGPUリソース情報 |
| index プロパティ | String | 各GPUのインデックス番号 |

### 出力先

Flinkリソースマネージャー

## 処理フロー

### 処理シーケンス

```
1. 設定読み込み
   └─ discovery-script.path, discovery-script.args取得
2. スクリプトパス解決
   └─ 相対パス→FLINK_HOME基準で解決
3. スクリプト検証
   └─ 存在確認・実行権限確認
4. スクリプト実行
   └─ Runtime.exec()でプロセス起動
5. 出力解析
   └─ カンマ区切りでGPUインデックス抽出
6. GPUInfo生成
   └─ 各インデックスからGPUInfoオブジェクト生成
```

### フローチャート

```mermaid
flowchart TD
    A[retrieveResourceInfo開始] --> B[gpuAmount > 0検証]
    B --> C[executeDiscoveryScript呼び出し]
    C --> D[Runtime.exec()でスクリプト実行]
    D --> E[タイムアウト待機（10秒）]
    E --> F{正常終了?}
    F -->|No| G[TimeoutException/FlinkException]
    F -->|Yes| H{終了コード=0?}
    H -->|No| I[FlinkException]
    H -->|Yes| J[stdout読み取り]
    J --> K[カンマで分割]
    K --> L[各インデックスからGPUInfo生成]
    L --> M[Set<GPUInfo>返却]
    G --> N[エラー処理]
    I --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | スクリプトパス必須 | discovery-script.pathが未設定の場合エラー | GPUDriver初期化時 |
| BR-002 | 実行権限必須 | スクリプトに実行権限がない場合エラー | GPUDriver初期化時 |
| BR-003 | タイムアウト10秒 | スクリプト実行が10秒を超えるとタイムアウト | retrieveResourceInfo呼び出し時 |
| BR-004 | 終了コード確認 | スクリプトが非0終了の場合エラー | スクリプト実行後 |
| BR-005 | 単一行出力 | 複数行出力の場合、最初の行のみ使用（警告出力） | スクリプト出力解析時 |

### 計算ロジック

- 相対パス解決: FLINK_HOME環境変数が設定されている場合はFLINK_HOME/path、未設定の場合は./path
- GPUインデックス解析: カンマ区切りで分割し、各要素をtrim()

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

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IllegalConfigurationException | discovery-script.pathが未設定 | 設定を追加 |
| - | FileNotFoundException | スクリプトファイルが存在しない | パスを確認 |
| - | FlinkException | スクリプトに実行権限がない | chmod +x |
| - | TimeoutException | スクリプト実行が10秒超過 | スクリプトを最適化 |
| - | FlinkException | スクリプトが非0終了 | スクリプトを修正 |
| - | IllegalArgumentException | gpuAmount <= 0 | 正の値を指定 |

### リトライ仕様

なし

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

なし

## パフォーマンス要件

- スクリプト実行タイムアウト: 10秒（DISCOVERY_SCRIPT_TIMEOUT_MS）

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

- 外部スクリプト実行のため、スクリプトの信頼性を確認すること
- スクリプトパスは絶対パスまたはFLINK_HOME相対で指定

## 備考

- デフォルトスクリプトパス: plugins/external-resource-gpu/nvidia-gpu-discovery.sh
- CUDA_VISIBLE_DEVICES環境変数との連携が一般的
- GPUInfo.getProperty("index")でGPUインデックス取得可能

---

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

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

### 推奨読解順序

#### Step 1: GPUDriverを理解する

GPU検出の中核ロジックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | GPUDriver.java | `flink-external-resources/flink-external-resource-gpu/src/main/java/org/apache/flink/externalresource/gpu/GPUDriver.java` | GPU検出ドライバー |

**主要処理フロー**:
- **54行目**: class GPUDriver implements ExternalResourceDriver - インターフェース実装
- **58行目**: DISCOVERY_SCRIPT_TIMEOUT_MS = 10000 - タイムアウト定数
- **63-96行目**: コンストラクタ - スクリプトパス検証・設定読み込み
- **64-71行目**: discovery-script.path設定取得と検証
- **73-79行目**: 相対パス→絶対パス解決（FLINK_HOME基準）
- **82-93行目**: ファイル存在・実行権限チェック
- **98-116行目**: retrieveResourceInfo() - GPUリソース検出
- **100-102行目**: gpuAmount正値チェック
- **105行目**: executeDiscoveryScript()呼び出し
- **107-112行目**: カンマ区切りでGPUインデックス解析
- **118-180行目**: executeDiscoveryScript() - スクリプト実行

**読解のコツ**: ExternalResourceDriverインターフェースのretrieveResourceInfo()がメイン。スクリプト出力をパースしてGPUInfoのSetを返す。

#### Step 2: スクリプト実行の詳細を理解する

外部プロセス実行とタイムアウト処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | GPUDriver.java | `flink-external-resources/flink-external-resource-gpu/src/main/java/org/apache/flink/externalresource/gpu/GPUDriver.java` | executeDiscoveryScript()メソッド |

**主要処理フロー**:
- **120-121行目**: コマンド文字列構築とRuntime.exec()
- **122-129行目**: stdout/stderrのBufferedReader準備
- **130-137行目**: タイムアウト付き待機（10秒）
- **139-165行目**: 終了コード確認とエラー処理
- **166-176行目**: stdout読み取り（複数行警告）
- **177-179行目**: finally節でプロセス強制終了

#### Step 3: 設定オプションを理解する

ConfigOptionによる設定定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | GPUDriverOptions.java | `flink-external-resources/flink-external-resource-gpu/src/main/java/org/apache/flink/externalresource/gpu/GPUDriverOptions.java` | 設定オプション定義 |

**主要処理フロー**:
- **30-31行目**: @PublicEvolving class GPUDriverOptions
- **37-55行目**: DISCOVERY_SCRIPT_PATH - スクリプトパス設定
- **40-43行目**: デフォルト値（plugins/external-resource-gpu/nvidia-gpu-discovery.sh）
- **57-71行目**: DISCOVERY_SCRIPT_ARG - スクリプト引数設定

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

GPU情報の保持クラスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | GPUInfo.java | `flink-external-resources/flink-external-resource-gpu/src/main/java/org/apache/flink/externalresource/gpu/GPUInfo.java` | GPU情報クラス |

**主要処理フロー**:
- **30行目**: class GPUInfo implements ExternalResourceInfo
- **32行目**: PROPERTY_KEY_INDEX = "index" - プロパティキー
- **34行目**: index フィールド - GPUインデックス
- **36-39行目**: コンストラクタ - null/空白チェック
- **63-69行目**: getProperty() - "index"キーでインデックス取得
- **71-74行目**: getKeys() - "index"のみ返却

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

```
ResourceManager (Flink Core)
    │
    └─ ExternalResourceDriver.retrieveResourceInfo(gpuAmount)
           │
           └─ GPUDriver.retrieveResourceInfo(gpuAmount)
                  │
                  ├─ Preconditions.checkArgument(gpuAmount > 0)
                  │
                  └─ executeDiscoveryScript(discoveryScriptFile, gpuAmount, args)
                         │
                         ├─ Runtime.getRuntime().exec(cmd)
                         │      └─ "script.sh <gpuAmount> <args>"
                         │
                         ├─ process.waitFor(10000, MILLISECONDS)
                         │      └─ タイムアウト検出
                         │
                         ├─ process.exitValue()
                         │      └─ 非0で FlinkException
                         │
                         └─ stdoutReader.lines()
                                └─ "0,1,2" → ["0", "1", "2"]
                                       │
                                       └─ GPUInfo(index) × N
                                              └─ Set<GPUInfo> 返却
```

### データフロー図

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

flink-conf.yaml
┌───────────────────────┐
│ external-resource.    │    GPUDriver初期化
│   gpu.param.          │───▶┌─────────────────────┐
│   discovery-script.   │    │ パス解決              │
│   path=xxx            │    │ 権限チェック          │
└───────────────────────┘    └─────────────────────┘
                                     │
                                     ▼
                              retrieveResourceInfo()
リソース要求                   ┌─────────────────────┐
┌───────────────────────┐    │ スクリプト実行        │
│ gpuAmount=2           │───▶│ "script.sh 2 args"  │
└───────────────────────┘    └─────────────────────┘
                                     │
                                     ▼
nvidia-gpu-discovery.sh       出力解析
┌───────────────────────┐    ┌─────────────────────┐
│ stdout: "0,1,2"       │───▶│ カンマ分割           │
└───────────────────────┘    │ GPUInfo生成          │
                              └─────────────────────┘
                                     │
                                     ▼
                              ┌─────────────────────┐
                              │ Set<GPUInfo>        │───▶ Flink ResourceManager
                              │   [GPU(0), GPU(1)]  │
                              └─────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| GPUDriver.java | `flink-external-resources/flink-external-resource-gpu/src/main/java/.../GPUDriver.java` | ソース | GPU検出ドライバー |
| GPUDriverFactory.java | `flink-external-resources/flink-external-resource-gpu/src/main/java/.../GPUDriverFactory.java` | ソース | ドライバーファクトリ |
| GPUDriverOptions.java | `flink-external-resources/flink-external-resource-gpu/src/main/java/.../GPUDriverOptions.java` | ソース | 設定オプション定義 |
| GPUInfo.java | `flink-external-resources/flink-external-resource-gpu/src/main/java/.../GPUInfo.java` | ソース | GPU情報データクラス |
| GPUDriverTest.java | `flink-external-resources/flink-external-resource-gpu/src/test/java/.../GPUDriverTest.java` | テスト | ドライバーテスト |
| GPUDiscoveryScriptTest.java | `flink-external-resources/flink-external-resource-gpu/src/test/java/.../GPUDiscoveryScriptTest.java` | テスト | スクリプトテスト |
