ビジュアライゼーションを通じたApache Sparkアプリケーションの理解

[Spark Visualizations: DAG, Timeline Views, and Streaming Statistics](https://www.databricks.com/blog/2015/06/22/understanding-your-spark-application-through-visualization.html)の翻訳です。

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

:::note info
本書は2015年の記事です。
:::

> 絵画の最も偉大な価値は、我々が見ることを決して期待していなかったことに気づくことを強制する際にもたらされます。- John Tukey

かつては、Apache Spark UIがユーザーのアプリケーションのデバッグ支援において重要となっていました。[最新のSpark 1.4リリース](https://www.databricks.com/blog/2015/06/11/announcing-apache-spark-1-4.html)で、Spark UIにデータビジュアライゼーションの波がやってきたことを嬉しく思っています。このリリースにおける新たなビジュアライゼーションの追加には、3つのメインコンポーネントがあります:

- Sparkイベントのタイムラインビュー
- 実行DAG
- Sparkストリーミング統計情報のビジュアライゼーション

この記事は、2つのパートのシリーズの最初のものであり、最初の2つのコンポーネントをカバーし、今後の記事で最後のコンポーネントをカバーします。

# Sparkイベントのタイムラインビュー

Sparkのイベントは、以前のバージョンのSparkからユーザーに表示されるAPIの一部となっていました。この最新リリースでは、Spark UIには相対的な順番やイベントの重なり具合をすぐに確認できるように、タイムラインのイベントとして表示します。

タイムラインビューは、3つのレベルで利用できます: *すべてのジョブに対して*、*一つのジョブ内で*、*一つのステージ内で*。ランディングページでは、タイムラインはすべてのジョブにおけるアプリケーション内のすべてのSparkイベントを表示します。以下の例を考えてみましょう:

![](https://www.databricks.com/wp-content/uploads/2015/06/Screen-Shot-2015-06-19-at-1.55.07-PM-1024x481.png)

ここでのイベントのシーケンスは非常にわかりやすいものとなっています。すべてのエグゼキューターが登録されたすぐ後に、アプリケーションは並列で4つのジョブを実行しており、一つは失敗していますが、残りは成功しています。そして、すべてのジョブが完了するとアプリケーションが終了し、それによってエグゼキューターが削除されています。一つのジョブをクリックしてみましょう。

![](https://www.databricks.com/wp-content/uploads/2015/06/Screen-Shot-2015-06-19-at-1.56.30-PM-1024x426.png)

このジョブは3つのファイルに対してワードカウントを実行しており、最後には結果を結合しています。タイムラインからは、3つのワードカウントステージはお互いに依存していないため、並列で実行されていることが明確になっています。しかし、最後の結合は最初の3つのステージの結果に依存しているので、対応するステージ(最後のcollect)はすべての先行するステージが完了するまでは開始しません。ステージの一つの中身をさらに見ていきましょう。

![](https://www.databricks.com/wp-content/uploads/2015/06/Screen-Shot-2015-06-19-at-1.57.36-PM.png)

このステージは、4台のマシンにまたがる20のパーティション(すべては表示していません)があります。それぞれのバーは、ステージ内の単一のタスクを表現しています。このタイムラインビューから、このステージに関するいくつかの洞察を得ることができます。最初に、パーティションはマシンに対して均等に分散されています。次に、タスク実行時間の大部分はネットワークやI/Oオーバーヘッドではなく生の計算時間となっていますが、これは非常に小さなデータをシャッフルしているので驚くべきことではありません。三つ目として、エグゼキューターに多くのコアを割り当てることで、並列度のレベルを向上させることができます。現時点では、それぞれのエグゼキューターは一度に2つよりも多いタスクを実行できないように見えます。

このタイムラインを用いて、Sparkの他の機能を説明する機会を活用したいと思います: *動的割り当て*です。この機能によって、Sparkがクラスターのリソースをより効率的に共有できるように、ワークロードをベースにして動的にエグゼキューターの数をスケールできるようになります。

![](https://www.databricks.com/wp-content/uploads/2015/06/Screen-Shot-2015-06-19-at-1.59.30-PM-1024x424.png)

最初に気づくのは、アプリケーションは最初にエグゼキューターを確保しておくのではなく、ジョブの過程でエグゼキューターを取得しているということです。そして、最初のジョブが完了するとすぐに、ジョブで使用された一連のエグゼキューターはアイドル状態になり、クラスターに返却されます。これによって、同じクラスターで稼働している他のアプリケーションが、同時にリソースを活用できるようになり、クラスターの利用率を向上させます。新たなジョブが投入された際にのみ、我々のSparkアプリケーションは実行のために新鮮なエグゼキューターのセットを取得します。

タイムラインでSparkイベントを参照する機能は、アプリケーションのボトルネックの特定に役立ちます。アプリケーションのデバックの次のステップは、特定のタスクやステージを、それを起動するSparkオペレーションにマッピングすることとなります。

# 実行DAG

最新のSparkリリースに追加される2つ目のビジュアライゼーションは、それぞれのジョブの実行DAGを表示します。Sparkにおいて、ジョブは以下のように見える有向非巡回グラフ(DAG)で整理された[RDD](https://www.databricks.com/blog/2016/07/14/a-tale-of-three-apache-spark-apis-rdds-dataframes-and-datasets.html)の依存関係のチェーンに関連づけられます:

![](https://www.databricks.com/wp-content/uploads/2015/06/Screen-Shot-2015-06-19-at-2.00.59-PM.png)

このジョブはシンプルなワードカウントを実行しています。最初に、HDFSにある入力ファイルを読み込むために*textFile*を実行し、それぞれの行を単語に分割するための*flatMap*オペレーションを実行し、`(word, 1)`を形成するためにの*map*オペレーションを実行し、最後にそれぞれの単語のカウントの合計を計算するために、*reduceByKey*オペレーションを実行します。

ビジュアライゼーションの青く塗られたボックスは、ユーザーがコードで呼び出すSparkオペレーションを表しています。これらのボックスのドットは、対応するオペレーションで作成されるRDDを表現しています。オペレーション自身は実行されるステージでグルーピングされます。

このビジュアライゼーションから得られるいくつかの観察事項があります。最初に、シャッフルによって分断されていないパイプラインオペレーションのSpark最適化が明らかになっています。特に、HDFCから入力パーティションを読み込んだ後に、それぞれのエグゼキューターが同じタスクでパーティションに、後続の*flatMap*と*map*を直接適用しており、別のステージを起動する必要性を排除しています。

二番目に、RDDの一つは最初のステージでキャッシュされています(緑でハイライトされています)。含まれているオペレーションはHDFSからの読み込みがあるので、このRDDのキャッシュは、このRDDに対する以降の計算処理は、HDFCからではなく少なくともメモリーにあるオリジナルファイルのサブセットにアクセスすることを意味します

DAGのビジュアライゼーションの価値は、複雑なジョブで最も発揮されます。例として、MLlibのAlternating Least Squares (ALS)実装は、2要素の行列の積を繰り返し近似します。この内部では、一連の*map, join, groupByKey*オペレーションが含まれます。

![](https://www.databricks.com/wp-content/uploads/2015/06/Screen-Shot-2015-06-19-at-2.02.25-PM.png)

ALSにおいては、アルゴリズムがそれぞれのイテレーションで積極的に以前計算した結果を再利用するので、適切な場所でのキャッシュがパフォーマンスにおいて重要です。DAGのビジュアライゼーションによって、ユーザーや開発者は一目で特定のRDDが適切にキャッシュされているのかを特定することができ、そうでない場合には、実装がなぜ遅いのかをクイックに理解できます。

タイムラインビューと同じように、DAGのビジュアライゼーションによってユーザーはステージを確認するためにクリックして、ステージ内の詳細を展開することができます。以下では、ALSの単一のステージのDAGビジュアライゼーションを示しています。

![](https://www.databricks.com/wp-content/uploads/2015/06/Screen-Shot-2015-06-19-at-2.03.21-PM.png)

ステージビューにおいては、このステージに属するすべてのRDDの詳細は自動で展開されます。ユーザは、推測したり、ジョブページの個々のドットにマウスカーソルを移動してチェックすることなしに、クイックに特定のRDDに関する情報を特定することができます。

最後になりますが、DAGのビジュアライゼーションとSpark SQLの暫定的なインテグレーションにハイライトしたいと思います。Spark SQLのユーザーは低レベルのSparkプリミティブではなく、高レベルの物理的なオペレーターに慣れ親しんでいるので、高レベルのオペレーターを表示すべきです。この結果は、背後の実行DAGにマッピングされるSQLクエリー計画のようなものになります。

![](https://www.databricks.com/wp-content/uploads/2015/06/Screen-Shot-2015-06-19-at-2.04.05-PM.png)

また、[Spark Streaming](https://www.databricks.com/blog/2015/07/30/diving-into-apache-spark-streamings-execution-model.html)とのインテグレーションはSpark 1.4で実装されていますが、別の記事でこちらは説明します。

近い将来、Spark UIはより適切な詳細を提供するために、より高次のライブラリのセマンティクスを検知するようになります。Spark SQLには既存のSparkストリーミングと同じようなタブが提供されます。Spark Core内では、ユーザーがRDDにマウスカーソルを合わせた際に、パーティションの数、呼び出しサイト、キャッシュ比率のような追加情報がDAG上に表示されるようになることでしょう。

:::note
**訳者註**
Spark 3.5時点ではすでにSQLタブが提供されています。
![Screenshot 2024-03-29 at 21.58.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/98526cfb-6d5f-31d2-b986-07a5699ec083.png)
:::

# サマリー

最新のSpark 1.4.0リリースでは、Spark UIにいくつかの主要なビジュアライゼーションが追加されました。この取り組みは、最初に直感的な方法でアプリケーションに関する詳細を提示することは、情報を提示するのと同じくらいに重要であるというプロジェクトの認識から派生したものです。今後のリリースでは、Spark Coreとそれをベースとした高次のライブラリの両方において、ユーザーがSpark UIによりアクセスしやすくするというトレンドを継続することになります。

SparkストリーミングにおけるUIの改善に関する記事を楽しみにしていてください！

# 謝辞

この記事で説明された機能は、Sparkコミュニティの何人かのコントリビューターによるものです。特にNTT Dataの `@sarutak` はタイムラインビュー機能のメインの開発者となっています。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

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