DatabricksにおけるApache Spark UIを用いたデバッグ

[Debugging with the Apache Spark UI \| Databricks on AWS](https://docs.databricks.com/clusters/debugging-spark-ui.html) [2022/7/19時点]の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

このガイドでは、お使いのApache Sparkアプリケーションの内部動作を確認するために利用可能なデバッグのいくつかのオプションをウォークスルーします。

- Spark UI
- ドライバーログ
- エグゼキューターログ

# Spark UI

ジョブをスタートすると、Spark UIがあなたのアプリケーションで何が起きているの関する情報を表示します。Spark UIを表示するには、アタッチしているクラスターをクリックしてSpark UIを選択します:
![](https://docs.databricks.com/_images/getting2-spark-ui.png)

## ストリーミングタブ

Spark UIに移動すると、このクラスターでストリーミングジョブを実行している際にはストリーミングタブを参照することができます。このクラスターでストリーミングジョブが実行されていない場合にはこのタブは表示されません。ストリーミングジョブを起動する際に例外が起きていないかを確認する方法を学ぶために[ドライバーログ](#ドライバーログ)までスキップすることもできます。

このページで最初に見るべきことは、あなたのストリーミングアプリケーションがデータソースから入力イベントを受信しているかどうかということです。この場合、ジョブは秒間1000イベントを受信しています。

アプリケーションが複数の入力ストリームを受信している場合、それぞれのレシーバーで受信しているイベントの数を表示させるために**Input Rate**リンクをクリックすることができます。
![](https://docs.databricks.com/_images/streaming-tab.png)

## 処理時間

下にスクロールすると**Processing Time**でグラフを参照することができます。これは、あなたのストリーミングジョブのパフォーマンスを理解絵するための重要なグラフの一つとなります。一般的な法則として、バッチ処理時間の80%でそれぞれのバッチを処理できていれば良好と言えます。

このアプリケーションでは、バッチ間隔は2秒です。平均処理時間は450msであり、バッチ間隔にうまく収まっています。平均処理時間がバッチ間隔に近づく、あるいは上回る場合、ストリーミングアプリケーションはキューを溜め始め、すぐにバックログとなり、結果的にはストリーミングジョブがダウンしてしまうことでしょう。
![](https://docs.databricks.com/_images/processing-time.png)

## 完了バッチ

ページの最後の方に行くと、完了バッチの一覧を参照することができます。このページでは、最新の完了バッチ1000件に関する詳細を表示しています。表からは、それぞれのバッチで処理されたイベントの数とそれらの処理時間を確認することができます。あるバッチで何が起きたのかに関して知りたいのであれば、バッチ詳細ページに移動するためにバッチのリンクをクリックすることができます。
![](https://docs.databricks.com/_images/completed-batches.png)

## バッチ詳細ページ

このページには、バッチに関して知りたいであろうすべての詳細が含まれています。キーとなる2つは:

- `Input`: バッチへの入力に関する詳細が含まれます。この場合、このバッチにおいてSpark構造化ストリーミングによって読み込まれたApache Kafkaのトピック、パーティション、オフセットの詳細が含まれています。`TextFileStream`の場合、このバッチで読み込まれたファイル名の一覧を参照することになります。これは、テキストファイルを読み込むストリーミングアプリケーションをデバッグする際のベストなスタート地点となります。
- `Processing`: このバッチの間に処理されたすべての詳細を含むジョブIDのリンクをクリックすることができます。

![](https://docs.databricks.com/_images/batch-details-page.png)

## ジョブ詳細ページ

ジョブ詳細ページにはDAGのビジュアライゼーションが表示されます。これは、すべてのバッチにおけるオペレーションの順序や依存関係を理解する際に有用です。この場合、バッチがKafkaのストリームから直接入力を読み込み、flat mapオペレーションを行い、mapオペレーションをおこなっていることを確認することができます。そして、結果として得られるストリームは、updateStateByKeyを用いてグローバルステートをアップデートするために使われています。(グレーのボックスはスキップされたステージであることを表しています。Sparkは再計算する必要がない場合にはいくつかのステージをスキップするほどにスマートです。データのチェックポイントが作成されたりキャッシュされると、Sparkはこれらのステージの再計算をスキップします。この場合、`updateStateBykey`によって、これらのステージは以前のバッチに対する依存関係に対応します。)

このページの下では、このバッチで実行されたジョブの一覧を確認することもできます。タスクレベルの処理にドリルダウンするためにdescriptionのリンクをクリックすることができます。
![](https://docs.databricks.com/_images/job-details-page1.png)
![](https://docs.databricks.com/_images/job-details-page2.png)

## タスク詳細ページ

これはSparkアプリケーションにおけるSpark UIで参照できる最も細かいレベルのデバッグとなります。このページには、このバッチで実行されたすべてのタスクに関する情報が含まれています。ストリーミングアプリケーションのパフォーマンス問題を調査しているのであれば、このページは実行されたタスクの数やどこで(どのエグゼキューターで)実行されたのか、シャッフルに関する情報を提供します。

:::note
**ティップス**
処理の間に十分な並列度が発揮されるように、クラスターの複数のエグゼキューター(ノード)でタスクが実行されていることを確認してください。単一のレシーバーを使用している場合、クラスターに一台以上のエグゼキューターがあったとしても、すべての作業を一つのエグゼキューターだけが処理してしまう場合があります。
:::
![](https://docs.databricks.com/_images/task-details-page.png)

## スレッドダンプ

スレッドダンプにはJVMのスレッドの状態のスナップショットが表示されます。

スレッドダンプは、特定のハングや処理の遅いタスクをデバッグする際に有用です。特定のタスクのスレッドダンプをSpark UIで参照するには:

1. **Jobs**タブをクリックします。
1. **Jobs**テーブルで、参照したスレッドダンプに対応するターゲットのジョブを探し出し、**Description**カラムのリンクをクリックします。
1. ジョブの**Stages**テーブルで、参照したいスレッドダンプに対応するターゲットのステージを探し出し、**Description**カラムのリンクをクリックします。
1. ステージの**Tasks**リストで、参照したいスレッドダンプに対応するターゲットのタスクを探し出し、**Task ID**と**Executor ID**の値をメモしておきます。
1. **Executors**タブをクリックします。
1. **Executors**テーブルで、メモした**Executor ID**に対応する**Executor ID**の値を含む行を探し出します。その行で、**Thread Dump**カラムのリンクをクリックします。
1. **Thread dump for executor**テーブルで、メモした**Task ID**のあとの**TID**を含む**Thread Name**カラムの行をクリックします。(タスクが処理を完了すると、マッチするスレッドを参照できなくなります)。タスクのダンプが表示されます。

また、スレッドダンプはドライバーがハングしているように見える場合(Sparkの進捗バーが表示されないなど)や、クエリーが進捗しない場合(Sparkの進捗バーが100%で止まってしまうなど)に問題をデバッグする際に役立ちます。ドライバーのスレッドダンプをSpark UIで参照するには:

1. **Executors**タブをクリックします。
1. **Executors**テーブルの**driver**行で、**Thread Dump**カラムのリンクをクリックします。ドライバーのスレッドダンプが表示されます。

# ドライバーログ

ドライバーログは2つの目的において有用です:

- 例外: 時にはSpark UIにストリーミングタブが表示されないことがあります。これは、何かしらの例外によってストリーミングジョブが起動しないためです。例外のスタックトレースを参照するためにドライバーログにドリルダウンすることができます。いくつかの場合では、ストリーミングジョブが適切に起動している場合があります。しかし、すべてのバッチが決して完了バッチのセクションに到達しないこともあり得ます。これらは全てが処理中の状態、あるいは失敗状態かもしれません。このような場合においても、ドライバーログは背後にある問題の特性を理解する役に立ちます。
- print: DAGの一部のprint文はログにも表示されます。

# エグゼキューターログ

特定のタスクの挙動がおかしくないか、あるいは特定タスクのログを参照したい場合にはエグゼキューターログが役立ちます。上で説明した多s区詳細ページから、タスクが実行されたエグゼキューターに移動することができます。移動したら、クラスターUIページに移動し、ノード数をクリックしてからmasterをクリックします。マスターページにはすべてのエグゼキューターが一覧されています。疑わしいタスクが実行されたエグゼキューターを選択し、log4jのアウトプットに移動することができます。
![](https://docs.databricks.com/_images/clusters.png)
![](https://docs.databricks.com/_images/spark-master.png)
![](https://docs.databricks.com/_images/executor-page.png)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)