# 機能設計書 17-Spark Web UI

## 概要

本ドキュメントは、Apache SparkのWeb UIについて、アプリケーション実行状況のリアルタイム可視化インターフェースの設計仕様を記述した機能設計書である。

### 本機能の処理概要

Sparkアプリケーションの実行状況をリアルタイムで可視化するWebインターフェースを提供し、ジョブ・ステージ・ストレージ・環境情報・Executor情報を表示する。Jettyベースの組み込みWebサーバーにより、HTMLページ、REST API、Prometheusメトリクスエンドポイントを提供する。

**業務上の目的・背景**：分散処理の実行状況をリアルタイムで把握し、パフォーマンス問題の早期発見やデバッグを行う必要がある。Web UIはブラウザベースのインターフェースを提供し、ジョブの進捗、タスクの分布、メモリ使用量、DAG構造などを視覚的に表示する。

**機能の利用シーン**：(1) アプリケーション実行中のジョブ進捗監視、(2) ステージ・タスクレベルのパフォーマンス分析、(3) Executorのリソース使用状況確認、(4) SQL実行計画の可視化、(5) ストリーミングクエリの監視。

**主要な処理内容**：
1. SparkUIクラスによるWebサーバーの初期化とタブ・ハンドラの登録
2. AppStatusStoreからのアプリケーション状態データの取得と表示
3. Jobs、Stages、Storage、Environment、Executorsの各タブ管理
4. REST API（/api/v1/）の提供
5. Prometheusメトリクスエンドポイントの提供（オプション）
6. ジョブ・ステージのKill操作サポート

**関連システム・外部連携**：AppStatusStore（KVStore経由のデータ取得）、Jetty HTTPサーバー、SecurityManager（アクセス制御）

**権限による制御**：SecurityManagerのACL設定により、UIの閲覧権限（view）と操作権限（modify/kill）を制御。spark.ui.killEnabledでKill操作の有効化を制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | All Jobs（全ジョブ一覧） | 主機能 | ジョブ一覧をActive/Completed/Failedに分類して表示 |
| 2 | Job Detail（ジョブ詳細） | 主機能 | 特定ジョブの統計情報・ステージ一覧を表示 |
| 3 | All Stages（全ステージ一覧） | 主機能 | 全ステージをActive/Pending/Complete/Skipped/Failedに分類 |
| 4 | Stage Detail（ステージ詳細） | 主機能 | ステージの統計・タスクメトリクス分布・タスク一覧を表示 |
| 5 | Pool Detail（プール詳細） | 主機能 | FAIRスケジューラのプール情報を表示 |
| 6 | Task Thread Dump | 主機能 | タスクのスレッドダンプ情報を表示 |
| 7 | Storage（ストレージ一覧） | 主機能 | 永続化RDD一覧とストリーミングレシーバブロック情報を表示 |
| 8 | RDD Detail（RDD詳細） | 主機能 | RDDのストレージ詳細を表示 |
| 9 | Environment（環境情報） | 主機能 | JVM・Spark・Hadoop・システムプロパティを表示 |
| 10 | Executors（エグゼキュータ一覧） | 主機能 | 全Executorのリソース使用状況・タスク統計を表示 |
| 11-29 | その他各種画面 | 主機能 | 各種詳細画面を提供 |

## 機能種別

Web UI / 可視化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| spark.ui.port | Int | No | UIポート番号 | デフォルト: 4040 |
| spark.ui.enabled | Boolean | No | UIの有効化 | デフォルト: true |
| spark.ui.killEnabled | Boolean | No | Kill操作の有効化 | デフォルト: true |
| spark.ui.prometheus.enabled | Boolean | No | Prometheusエンドポイント有効化 | デフォルト: false |

### 入力データソース

AppStatusStore（InMemoryStoreまたはLevelDB/RocksDBバックエンドのKVStoreからアプリケーション状態を取得）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| HTMLページ | String | 各タブのHTML出力 |
| REST API応答 | JSON | /api/v1/以下のJSON応答 |
| Prometheusメトリクス | String | /metrics/prometheus形式の出力 |

### 出力先

HTTPレスポンスとしてWebブラウザ・APIクライアントに返却。

## 処理フロー

### 処理シーケンス

```
1. SparkUI生成
   └─ SparkUI.create()でAppStatusStore、SparkConf、SecurityManagerを設定
2. initialize()
   └─ JobsTab, StagesTab, StorageTab, EnvironmentTab, ExecutorsTab等を登録
3. bind()
   └─ Jettyサーバーを起動しポートをバインド
4. attachAllHandlers()
   └─ 全ハンドラをサーバーに接続し、リクエスト受付開始
5. リクエスト処理
   └─ 各TabのPageがAppStatusStoreからデータを取得しHTML/JSONを生成
6. stop()
   └─ Jettyサーバーを停止
```

### フローチャート

```mermaid
flowchart TD
    A[SparkUI.create] --> B[initialize]
    B --> C[JobsTab登録]
    B --> D[StagesTab登録]
    B --> E[StorageTab登録]
    B --> F[EnvironmentTab登録]
    B --> G[ExecutorsTab登録]
    B --> H[REST API登録]
    B --> I{Prometheus有効?}
    I -->|Yes| J[Prometheusハンドラ登録]
    I -->|No| K[スキップ]
    B --> L[Kill用リダイレクトハンドラ登録]
    L --> M[bind Jettyサーバー]
    M --> N[attachAllHandlers]
    N --> O[リクエスト待機]
    O --> P[AppStatusStoreからデータ取得]
    P --> Q[HTML/JSON生成・応答]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-17-01 | ルートリダイレクト | "/" へのアクセスは "/jobs/" にリダイレクト | 全アクセス |
| BR-17-02 | Kill操作制御 | spark.ui.killEnabledがfalseの場合Kill操作を無効化 | Kill操作時 |
| BR-17-03 | Kill HTTPメソッド | GET/POST両方でKill操作を受付（YARN AMプロキシ互換） | Kill操作時 |
| BR-17-04 | 起動時初期ハンドラ | 起動中は「Spark is starting up」メッセージを表示 | 起動処理中 |
| BR-17-05 | 静的リソース配信 | org/apache/spark/ui/staticディレクトリから静的ファイルを配信 | 全アクセス |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | AppStatusStore | SELECT | KVStoreからジョブ・ステージ・タスク情報を取得 |

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

AppStatusStoreはKVStoreのラッパーであり、InMemoryStoreまたはファイルベースのストアから読み取り専用でデータを取得する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | BindException | ポートが既に使用中 | logErrorでエラーログ出力後、System.exit(1) |
| - | NoSuchElementException | 存在しないappIdへのアクセス | 例外スロー |

### リトライ仕様

ポートバインド失敗時のリトライは行わない。

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

該当なし（読み取り専用のWeb UI）

## パフォーマンス要件

Jettyスレッドプールによる並行リクエスト処理。AppStatusStoreのKVStoreアクセスは非同期で行われる。

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

- SecurityManagerのACLによるアクセス制御
- SSL/TLS通信の暗号化設定（spark.ssl.ui.*）
- XSS対策のためのHTMLエスケープ処理

## 備考

- SparkUIはUIRootトレイトを実装し、History Serverとの互換性を持つ
- DriverLogタブはspark.driver.log.localDirが設定されている場合のみ表示
- StreamingJobProgressListenerのオプション設定によりDStreamsの情報も表示可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | AppStatusStore.scala | `core/src/main/scala/org/apache/spark/status/AppStatusStore.scala` | アプリケーション状態データへのアクセスAPI |

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SparkUI.scala | `core/src/main/scala/org/apache/spark/ui/SparkUI.scala` | メインクラス。initialize(), bind(), attachAllHandlers()の流れ |

**主要処理フロー**:
1. **42-54行目**: コンストラクタでAppStatusStore, SparkConf等を受け取る
2. **56行目**: killEnabledの設定読み込み
3. **98-126行目**: initialize()で各タブ・ハンドラを登録
4. **128行目**: initialize()がコンストラクタ内で呼び出し
5. **151-162行目**: bind()でJettyサーバーを初期化・起動
6. **77-85行目**: attachAllHandlers()で全ハンドラをサーバーに接続

#### Step 3: 各タブの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | JobsTab.scala | `core/src/main/scala/org/apache/spark/ui/jobs/JobsTab.scala` | Jobs一覧タブの実装 |
| 3-2 | StagesTab.scala | `core/src/main/scala/org/apache/spark/ui/jobs/StagesTab.scala` | Stages一覧タブの実装 |
| 3-3 | StorageTab.scala | `core/src/main/scala/org/apache/spark/ui/storage/StorageTab.scala` | Storage一覧タブの実装 |

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

```
SparkContext
    │
    ├─ SparkUI.create()
    │      └─ new SparkUI(store, sc, conf, securityManager, ...)
    │           └─ initialize()
    │                ├─ JobsTab(this, store) → attachTab
    │                ├─ StagesTab(this, store) → attachTab
    │                ├─ StorageTab(this, store) → attachTab
    │                ├─ EnvironmentTab(this, store) → attachTab
    │                ├─ ExecutorsTab(this) → attachTab
    │                ├─ ApiRootResource.getServletHandler (/api/v1/)
    │                └─ PrometheusResource (optional)
    │
    ├─ sparkUI.bind()
    │      └─ Jetty Server起動 + initHandler登録
    │
    └─ sparkUI.attachAllHandlers()
         └─ 全handlers → Server.addHandler
```

### データフロー図

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

HTTPリクエスト       ───▶ Jetty Server           ───▶ HTMLページ
(ブラウザ)                ├─ ServletHandler              (各タブ)
                          └─ Tab.Page.render()

AppStatusStore      ───▶ KVStore               ───▶ ジョブ/ステージ/
(状態データ)               (InMemory/LevelDB)         タスクデータ

REST APIリクエスト   ───▶ ApiRootResource        ───▶ JSON応答
(/api/v1/)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SparkUI.scala | `core/src/main/scala/org/apache/spark/ui/SparkUI.scala` | ソース | Web UIのメインクラス |
| WebUI.scala | `core/src/main/scala/org/apache/spark/ui/WebUI.scala` | ソース | WebUI基底クラス |
| JettyUtils.scala | `core/src/main/scala/org/apache/spark/ui/JettyUtils.scala` | ソース | Jettyユーティリティ |
| JobsTab.scala | `core/src/main/scala/org/apache/spark/ui/jobs/JobsTab.scala` | ソース | Jobsタブ |
| StagesTab.scala | `core/src/main/scala/org/apache/spark/ui/jobs/StagesTab.scala` | ソース | Stagesタブ |
| StorageTab.scala | `core/src/main/scala/org/apache/spark/ui/storage/StorageTab.scala` | ソース | Storageタブ |
| EnvironmentTab.scala | `core/src/main/scala/org/apache/spark/ui/env/EnvironmentTab.scala` | ソース | Environmentタブ |
| ExecutorsTab.scala | `core/src/main/scala/org/apache/spark/ui/exec/ExecutorsTab.scala` | ソース | Executorsタブ |
| ApiRootResource.scala | `core/src/main/scala/org/apache/spark/status/api/v1/ApiRootResource.scala` | ソース | REST API |
| AppStatusStore.scala | `core/src/main/scala/org/apache/spark/status/AppStatusStore.scala` | ソース | アプリケーション状態ストア |
