YARNでSparkジョブを実行するときに、コア数とエグゼキュータ数の関係を理解しようとしています。
テスト環境は以下のとおりです。
ネットワーク:1Gb
スパークバージョン:1.0.0
Hadoopのバージョン:2.4.0(Hortonworks HDP 2.1)
スパークジョブフロー:sc.textFile - > filter - > map - > filter - > mapToPair - > reduceByKey - > map - > saveAsTextFile
入力データ
出力
ジョブは以下の構成で実行されました。
--master yarn-client --executor-memory 19G --executor-cores 7 --num-executors 3
(データノードごとのエクゼキュータ、コアと同じくらい使用)
--master yarn-client --executor-memory 19G --executor-cores 4 --num-executors 3
(コア数の削減)
--master yarn-client --executor-memory 4G --executor-cores 2 --num-executors 12
(より少ないコア、より多くのexecutor)
経過時間
50分15秒
55分48秒
31分23秒
驚いたことに、(3)のほうがずっと早いです。
シャッフルするとエグゼキュータ間の通信が少なくなるため、(1)のほうが速いと思いました。
(1)のコア数は(3)より少なくても、2)がうまく機能したのでコア数は重要な要素ではありません。
(pwilmotの回答の後に以下が追加されました。)
情報については、パフォーマンスモニタの画面キャプチャは次のとおりです。
グラフは大きく2つのセクションに分かれています。
グラフが示すように、(1)は与えられたのと同じくらいのCPUパワーを使用できます。だから、それはスレッドの数の問題ではないかもしれません。
この結果をどのように説明しますか?
これらすべてをもう少し具体的にするために、可能な限り多くのクラスターを使用するようにSparkアプリを構成する実用的な例を次に示します。NodeManagerを実行する6ノードのクラスターそれぞれが16個のコアと64GBのメモリを搭載。 NodeManagerの容量、yarn.nodemanager.resource.memory-mbおよびyarn.nodemanager.resource.cpu-vcoresは、おそらくそれぞれ63 * 1024 = 64512(メガバイト)および15に設定する必要があります。ノードがOSデーモンとHadoopデーモンを実行するためにいくつかのリソースを必要とするため、リソースの100%をYARNコンテナーに割り当てることは避けます。この場合、これらのシステムプロセスにギガバイトとコアを残します。 Cloudera Managerは、これらを考慮し、これらのYARNプロパティを自動的に設定することで役立ちます。
おそらく最初の衝動は、 - num-executors 6 --executor-cores 15 --executor-memory 63Gを使用することです。ただし、これは間違ったアプローチです。
63GB +エグゼキュータのメモリオーバーヘッドは、NodeManagerの63GBの容量に収まりません。アプリケーションマスターはいずれかのノードでコアを使用するため、そのノードに15コアのエクゼキュータを配置する余地はありません。エクゼキュータあたり15コアでは、HDFSのI/Oスループットが低下する可能性があります。
もっと良い方法は - num-executors 17 --executor-cores 5 --executor-memory 19Gを使うことです。どうして?
この設定により、AMを持つノードを除くすべてのノードに3つのエグゼキュータが作成されます。これには2つのエグゼキュータが含まれます。 --executor-memoryは、(ノードあたり63/3エクゼキュータ)= 21として導出されました。21 * 0.07 = 1.47。 21 - 1.47〜19。
説明は、clouderaのブログの記事にありました http://blog.cloudera.com/blog/2015/03/how-to-tune-your-Apache-spark-jobs-part-2/ =
スパークアプリをHDFS上で実行すると、 Sandy Ryza によると
私は、HDFSクライアントが大量の並行スレッドで問題を抱えていることに気付きました。大まかに言って、エクゼキュータあたり最大で5つのタスクでフル書き込みスループットを達成できるため、エクゼキュータあたりのコア数をその数より少なくすることをお勧めします。
だから私はあなたの最初の設定が悪いHDFSのI/Oスループットのためである第3のものより遅いと信じる
私は自分自身でこれらの設定を試したことはないので、これは単なる憶測ですが、分散システムの通常のコアとスレッドとしてこの問題を考えるなら、あなたのクラスタでは最大12コア(4 * 3マシン)と24スレッドを使うことができます。 (8×3機)。最初の2つの例では、ジョブにかなりの数のコア(潜在的な計算スペース)を与えていますが、それらのコアで実行するスレッド(ジョブ)の数が非常に限られているため、割り当てられた処理能力をあまり使用できません。したがって、割り当てられている計算リソースが増えても、ジョブは遅くなります。
あなたはあなたの懸念がシャッフルステップにあったと述べています - シャッフルステップのオーバーヘッドを制限することはいいことですが、一般的にクラスタの並列化を利用することがもっと重要です。極端なケース、つまりシャッフルのないシングルスレッドプログラムについて考えてみましょう。
簡単な答え: tgbaggio が正しいと思います。あなたはあなたのexecutorのHDFSスループット限界を打ちます。
私はここでの答えはここでのいくつかの勧告より少し簡単かもしれないと思います。
私にとっての手がかりは、クラスターネットワークグラフにあります。実行1では、使用率は約50 Mバイト/秒で安定しています。実行3では、安定した使用率が倍増し、約100 Mバイト/秒になります。
clouderaブログ投稿DzOrd が共有することから、この重要な引用を見ることができます:
私は、HDFSクライアントが大量の並行スレッドで問題を抱えていることに気付きました。大まかな推測として、1エクゼキュータあたり最大5つのタスクでフルライトスループットを達成できると考えられるため、エクゼキュータあたりのコア数をその数より少なくするのが良いでしょう。
それで、それが本当ならば、私たちがどんなパフォーマンスを期待するかを見るためにいくつかの計算をしましょう。
ジョブが同時実行性(スレッド数)によって100%制限されている場合。実行時間はスレッド数と完全に逆相関することが予想されます。
ratio_num_threads = nthread_job1 / nthread_job3 = 15/24 = 0.625
inv_ratio_runtime = 1/(duration_job1 / duration_job3) = 1/(50/31) = 31/50 = 0.62
だからratio_num_threads ~= inv_ratio_runtime
、それは私たちがネットワークに制限されているようです。
これと同じ効果が、実行1と実行2の違いを説明しています。
有効スレッド数とランタイムの比較
ratio_num_threads = nthread_job2 / nthread_job1 = 12/15 = 0.8
inv_ratio_runtime = 1/(duration_job2 / duration_job1) = 1/(55/50) = 50/55 = 0.91
前回の比較ほど完璧ではありませんが、スレッドを失うと、パフォーマンスが同様に低下します。
最後の話では、スレッド数が多いほどパフォーマンスが向上するのはなぜでしょうか。特に。 CPUの数よりも多くのスレッド?
並列性(データを複数のCPUに分割することによって得られるもの)と並行性(単一のCPUで作業するために複数のスレッドを使用するときに得られるもの)の違いについての良い説明は、Rob Pikeによるこの素晴らしい記事で提供されます。 並行性は並列処理ではありません 。
簡単に説明すると、Sparkジョブがファイルシステムやネットワークと対話している場合、CPUはそれらのインターフェイスとの通信を待機するのに多くの時間を費やし、実際には「仕事をする」のに多くの時間を費やしません。これらのCPUに一度に1つ以上のタスクを実行させることで、待機時間と作業時間が短縮され、パフォーマンスが向上します。
で入手可能な優れたリソースから RStudioのSparklyrパッケージページ :
スパーク定義:
Sparkの命名法の簡単な定義をいくつか提供すると便利かもしれません。
ノード:サーバ
ワーカーノード:クラスタの一部であり、Sparkジョブを実行できるサーバー
マスターノード:ワーカーノードを調整するサーバー。
Executor:ノード内の一種の仮想マシン。 1つのノードは複数のエグゼキュータを持つことができます。
ドライバノード:Sparkセッションを開始するノード。通常、これはsparklyrが配置されているサーバーになります。
Driver(Executor):Driver NodeもExecutorリストに表示されます。
私が思う最初の2つの設定には小さな問題があります。スレッドとコアの概念は次のとおりです。スレッド化の概念は、コアが理想的であればそのコアを使用してデータを処理することです。そのため、最初の2つのケースではメモリが十分に活用されていません。この例をベンチマークしたい場合は、各マシンに10コアを超えるマシンを選択してください。次にベンチマークを行います。
しかし、エグゼキュータあたり5コア以上を与えてはいけません。I/ Oパフォーマンスにボトルネックが生じるでしょう。
したがって、このベンチマークを実行するのに最適なマシンは、10コアのデータノードです。
データノードマシンスペック:CPU:コアi7〜4790(コア数:10、スレッド数:20)RAM:32GB(8GB×4)HDD:8TB(2TB×4)
Spark動的割り当ては柔軟性を与え、リソースを動的に割り当てます。この数で最小および最大エグゼキュータを与えることができます。また、アプリケーションの起動時に起動する必要があるエグゼキュータの数も指定できます。
同様に以下をお読みください。
http://spark.Apache.org/docs/latest/configuration.html#dynamic-allocation
主な理由の1つは地域性だと思います。入力ファイルのサイズは165Gです。ファイルの関連ブロックは確実に複数のDataNodeに分散されているため、より多くのエグゼキュータがネットワークコピーを回避することができます。
Executorの数をブロック数と同じに設定してみてください。