# バッチ設計書 20-spark-submit

## 概要

本ドキュメントは、Sparkアプリケーションをクラスタに投入するシェルスクリプト `spark-submit` のバッチ設計書である。Sparkのメインエントリーポイントとして、ユーザーのアプリケーションJAR/Pythonスクリプト/Rスクリプト等をSparkクラスタに投入・実行する。

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

`spark-submit` は、Sparkアプリケーションをクラスタに投入するためのコマンドラインインターフェースである。内部的には `find-spark-home` でSPARK_HOMEを特定した後、`spark-class` コマンドを使用して `org.apache.spark.deploy.SparkSubmit` クラスを実行する。SparkSubmitクラスがアプリケーションのデプロイモード（client/cluster）、マスターURL、クラスパス構成等を処理し、最終的にユーザーアプリケーションを実行する。

**業務上の目的・背景**：Sparkアプリケーション（バッチ処理、ETL、機械学習ジョブ等）をクラスタ上で実行するためには、アプリケーションJARやスクリプトをクラスタマネージャーに投入する統一的なインターフェースが必要である。spark-submitはSpark Standalone、YARN、Mesos、Kubernetes等の複数のクラスタマネージャーに対応した統一的な投入インターフェースを提供し、デプロイモードや実行環境の違いを抽象化する。

**バッチの実行タイミング**：手動実行、cronジョブ、ワークフローエンジン（Airflow、Oozie等）からのスケジュール実行、または他のSparkスクリプト（start-thriftserver.sh、start-connect-server.sh等）からの内部呼び出し。

**主要な処理内容**：
1. SPARK_HOME環境変数の設定（find-spark-home経由）
2. PYTHONHASHSEEDの設定（Python 3.3+のハッシュランダム化を無効化）
3. `spark-class` 経由で `org.apache.spark.deploy.SparkSubmit` クラスを実行
4. SparkSubmitクラスが引数を解析し、アプリケーションを適切なクラスタマネージャーに投入

**前後の処理との関連**：多くのスクリプトから呼び出される中核的なコマンドである。`start-thriftserver.sh`（No.12）、`start-connect-server.sh`（No.14）は `spark-daemon.sh`（No.16）の submit モード経由で本コマンドを利用する。内部では `find-spark-home`（No.31関連）と `spark-class`（No.21関連）を使用する。

**影響範囲**：Sparkクラスタ上のリソース（CPU、メモリ、ディスク）を消費する。クラスタマネージャーのジョブキューに影響を与える。アプリケーションが処理するデータソース（HDFS、S3、データベース等）に対する読み書きが発生する。

## バッチ種別

クライアント実行（アプリケーション投入）

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（ユースケースに依存） |
| 実行時刻 | 任意 |
| 実行曜日 | 該当なし |
| 実行日 | 該当なし |
| トリガー | 手動 / cron / ワークフローエンジン / 他スクリプトからの呼び出し |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| SPARK_HOME | 環境変数が設定済み、または `find-spark-home` で自動検出可能であること |
| spark-class | `${SPARK_HOME}/bin/spark-class` が存在し実行可能であること |
| find-spark-home | `${SPARK_HOME}/bin/find-spark-home` が存在すること |
| Java実行環境 | JAVA_HOMEまたはPATHにjavaコマンドが存在すること |
| Spark JARs | `${SPARK_HOME}/jars` ディレクトリが存在すること |
| クラスタ接続 | 指定されたマスターURLのクラスタマネージャーに接続可能であること |

### 実行可否判定

SparkSubmitクラス内部で引数の妥当性チェックが行われる。不正な引数やクラスタ接続失敗時はエラーメッセージを出力して終了する。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| --class | 文字列 | No（JARの場合はYes） | - | アプリケーションのメインクラス名 |
| --master | 文字列 | No | local[*] | クラスタマネージャーURL（local, spark://, yarn, mesos://, k8s://） |
| --deploy-mode | 文字列 | No | client | デプロイモード（client / cluster） |
| --conf | キー=値 | No | - | Spark設定プロパティ |
| --name | 文字列 | No | - | アプリケーション名 |
| --jars | 文字列 | No | - | 追加JARファイル（カンマ区切り） |
| --py-files | 文字列 | No | - | Pythonファイル（.py, .zip, .egg） |
| --files | 文字列 | No | - | ワーキングディレクトリに配置するファイル |
| --driver-memory | 文字列 | No | 1g | ドライバーのメモリ量 |
| --executor-memory | 文字列 | No | 1g | エグゼキュータのメモリ量 |
| --num-executors | 数値 | No | - | エグゼキュータ数 |
| application-jar/script | 文字列 | Yes | - | アプリケーションJAR/Pythonスクリプト/Rスクリプト |
| [application-arguments] | 文字列 | No | - | アプリケーションに渡す引数 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| アプリケーションJAR/スクリプト | JAR/py/R | 実行対象のアプリケーション |
| spark-env.sh | シェルスクリプト | Spark環境設定（find-spark-home/load-spark-env.sh経由） |
| spark-defaults.conf | プロパティファイル | Sparkデフォルト設定 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| 標準出力 | テキスト | アプリケーションの出力 |
| 標準エラー出力 | テキスト | Sparkフレームワークのログ出力 |

### 出力ファイル仕様

本スクリプト自体はファイル出力を行わない。実行されるアプリケーションの出力仕様に依存する。

## 処理フロー

### 処理シーケンス

```
1. SPARK_HOME環境変数の確認・設定
   └─ find-spark-home経由で検出
2. PYTHONHASHSEED=0 の設定
   └─ Python 3.3+のハッシュランダム化を無効化（再現性確保）
3. spark-class の呼び出し
   └─ exec spark-class org.apache.spark.deploy.SparkSubmit "$@"
4. spark-class内部の処理
   ├─ load-spark-env.shの読み込み
   ├─ Java実行環境の検出
   ├─ クラスパスの構築（${SPARK_HOME}/jars/*）
   ├─ ランチャー（org.apache.spark.launcher.Main）の実行
   └─ ランチャーが構築したコマンドラインでSparkSubmitを起動
5. SparkSubmitクラスの実行
   └─ 引数解析、クラスタマネージャー接続、アプリケーション実行
```

### フローチャート

```mermaid
flowchart TD
    A[spark-submit実行] --> B{SPARK_HOME設定済み?}
    B -->|No| C[find-spark-home実行]
    B -->|Yes| D[PYTHONHASHSEED=0設定]
    C --> D
    D --> E["exec spark-class SparkSubmit 引数"]
    E --> F[load-spark-env.sh読み込み]
    F --> G[Java実行環境検出]
    G --> H[クラスパス構築]
    H --> I[ランチャー実行]
    I --> J[SparkSubmit起動]
    J --> K[引数解析]
    K --> L{アプリケーション種別}
    L -->|JAR| M[Javaアプリケーション実行]
    L -->|Python| N[Pythonアプリケーション実行]
    L -->|R| O[Rアプリケーション実行]
    M --> P[アプリケーション終了]
    N --> P
    O --> P
```

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

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

本スクリプト自体はデータベース操作を行わない。投入されるアプリケーションのデータベース操作はアプリケーション固有。

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

該当なし（スクリプトレベルでは該当なし）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 終了コード1 | JAVA_HOME未設定 | JavaがPATHにもJAVA_HOMEにもない | Java実行環境をインストールし、JAVA_HOMEを設定 |
| 終了コード1 | Spark JARs不在 | ${SPARK_HOME}/jarsが存在しない | Sparkをビルドまたは正しくインストール |
| 終了コード非0 | ランチャー失敗 | ランチャーの終了コードが0でない | エラーメッセージを確認し、クラスパスや設定を見直し |
| 終了コード非0 | アプリケーション失敗 | 投入されたアプリケーションの実行エラー | アプリケーションのログを確認 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（スクリプトレベル） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

### 障害時対応

- Java環境の問題: JAVA_HOMEの設定確認、Javaバージョンの互換性確認
- クラスパスの問題: Sparkのビルド状態確認、jarsディレクトリの確認
- アプリケーションエラー: Sparkアプリケーションのログ（driver/executor）を確認
- クラスタ接続エラー: マスターURL、ネットワーク接続、クラスタマネージャーの稼働状況を確認

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 該当なし（スクリプトレベル。アプリケーション内部のトランザクションはアプリケーション固有） |
| コミットタイミング | 該当なし |
| ロールバック条件 | 該当なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 1アプリケーション/実行 |
| 目標処理時間 | アプリケーション固有（スクリプト自体の起動オーバーヘッドは数秒） |
| メモリ使用量上限 | ランチャーJVMは最大128MB（-Xmx128m）。アプリケーションのメモリはSpark設定に依存 |

## 排他制御

本スクリプト自体に排他制御はない。複数のspark-submitを同時実行可能。クラスタリソースの排他制御はクラスタマネージャー（YARN、Kubernetes等）が管理する。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 起動コマンドログ | spark-class内 | ランチャーが生成したJava実行コマンド |
| アプリケーションログ | アプリケーション実行中 | Sparkフレームワークおよびアプリケーションのログ（log4j経由） |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 該当なし | - | 本スクリプト自体に監視・アラート機能は実装されていない。Spark UIやクラスタマネージャーのUIで監視可能 |

## 備考

- `exec` コマンドで `spark-class` を呼び出しているため、本スクリプトのプロセスは `spark-class` に置き換わる。
- `PYTHONHASHSEED=0` の設定により、Python 3.3+のハッシュランダム化が無効化される。これはPySparkでの処理結果の再現性を確保するために必要。
- ランチャーJVM（org.apache.spark.launcher.Main）は最大128MBのメモリで実行され、実際のSparkアプリケーションの起動コマンドを生成する。
- `spark-class` 内部では、ランチャーの出力をNULL文字区切りで解析し、最終的な実行コマンドを構築する。これにより、特殊文字を含む引数も正しく処理される。
- ソースファイルパス: `bin/spark-submit`
