Sparkでは、ステージはどのようにタスクに分割されますか?


143

以下では、すべての時点で1つのSparkジョブのみが実行されていると仮定します。

これまでに得たもの

Sparkで何が発生するかを理解します。

  1. ときにSparkContext作成され、各ワーカーノードは、executorを開始します。エグゼキューターは、ドライバープログラムに接続する個別のプロセス(JVM)です。各エグゼキュータは、ドライバプログラムのjarを持っています。ドライバーを終了すると、実行プログラムがシャットダウンされます。各エグゼキュータはいくつかのパーティションを保持できます。
  2. ジョブが実行されると、系統グラフに従って実行計画が作成されます。
  3. 実行ジョブは複数のステージに分割され、ステージには(リネージュグラフで)隣接する変換とアクションがすべて含まれますが、シャッフルは含まれません。したがって、ステージはシャッフルによって分離されます。

画像1

という事は承知しています

  • タスクは、Functionオブジェクトをシリアル化することによってドライバーからエグゼキューターに送信されるコマンドです。
  • エグゼキューターは、コマンド(タスク)を(ドライバーjarを使用して)逆シリアル化し、パーティションで実行します。

だが

質問

ステージをこれらのタスクに分割するにはどうすればよいですか?

具体的には:

  1. タスクは変換とアクションによって決定されますか、それとも複数の変換/アクションがタスクに含まれる可能性がありますか?
  2. タスクはパーティションによって決定されますか(パーティションごとのステージごとに1つのタスクなど)。
  3. タスクはノードによって決定されますか(ノードごとのステージごとに1つのタスクなど)?

私が思うこと(たとえ正しいとしても、部分的な答えのみ)

https://0x0fff.com/spark-architecture-shuffle、シャッフルを画像で説明されています

ここに画像の説明を入力してください

そして、私はルールが

ノードの数に関係なく、各ステージは#number-of-partitionsタスクに分割されます

最初の画像では、3つのマップタスクと3つの縮小タスクがあると思います。

0x0fffからの画像の場合、8つのマップタスクと3つの削減タスクがあると思います(オレンジとダークグリーンのファイルが3つしかない場合)。

いずれにせよ未解決の質問

あれは正しいですか?しかし、それが正しいとしても、複数の操作(たとえば、複数のマップ)が1つのタスク内にあるか、操作ごとに1つのタスクに分かれているかに関わらず、上記の私の質問にはまだ回答がありません。

他の人が言うこと

Sparkのタスクとは何ですか?Sparkワーカーはjarファイルをどのように実行しますか?そして、Apache Sparkスケジューラーはどのようにファイルをタスクに分割しますか?似ていますが、質問が明確に回答されているとは思いませんでした。

回答:


52

ここにはかなりいいアウトラインがあります。あなたの質問に答えるために

  • それぞれのデータのパーティションごとに個別に起動する必要task ありますstage。各パーティションが異なる物理的な場所に存在する可能性があることを考慮してください-たとえば、ローカルファイルシステムのHDFSまたはディレクトリ/ボリューム内のブロック。

Stages の送信はによって駆動されることに注意してくださいDAG Scheduler。これは、相互に依存しないステージをクラスターに送信して並列実行できることを意味します。これにより、クラスターの並列化機能が最大化されます。したがって、データフローの操作が同時に発生する可能性がある場合は、複数のステージが起動されることが予想されます。

次のおもちゃの例では、次のタイプの操作を実行していることがわかります。

  • 2つのデータソースを読み込む
  • 両方のデータソースに対して個別にマップ操作を実行する
  • 彼らに参加する
  • 結果に対していくつかのマップおよびフィルター操作を実行します
  • 結果を保存する

それでは、最終的に何ステージになるのでしょうか。

  • 2つのデータソースを並行してロードするための各1ステージ= 2ステージ
  • 他の2つのステージに依存するjoinを表す3番目のステージ
  • 注:結合されたデータを処理する後続操作はすべて、順次実行する必要があるため、同じステージで実行できます。追加のステージを起動しても、前の操作が完了するまで作業を開始できないため、メリットはありません。

これがおもちゃのプログラムです

val sfi  = sc.textFile("/data/blah/input").map{ x => val xi = x.toInt; (xi,xi*xi) }
val sp = sc.parallelize{ (0 until 1000).map{ x => (x,x * x+1) }}
val spj = sfi.join(sp)
val sm = spj.mapPartitions{ iter => iter.map{ case (k,(v1,v2)) => (k, v1+v2) }}
val sf = sm.filter{ case (k,v) => v % 10 == 0 }
sf.saveAsTextFile("/data/blah/out")

そして、これが結果のDAGです

ここに画像の説明を入力してください

今:いくつのタスク?タスクの数は

Stage* #Partitions in the stage)の合計


2
ありがとう!私のテキストに関して、あなたの答えを詳しく説明してください:1)私のステージの定義は包括的ではありませんか?ステージには並列処理が可能な操作を含めることができないという要件を逃したようです。それとも、私の説明はすでにそれを厳密に暗示していますか?2)ジョブに対して実行する必要があるタスクの数は、パーティションの数によって決まりますが、プロセッサやノードの数ではありません。同時に実行できるタスクの数は、プロセッサーですよね?3)タスクに複数の操作を含めることができますか?
Make42

1
4)最後の文はどういう意味ですか?結局のところ、パーティションの数はステージごとに異なる可能性があります。これが、すべてのステージでジョブを構成する方法だということですか?
Make42 2016年

@ Make42もちろん、パーティションの数はステージごとに異なります-あなたは正しいです。sum(..)その変動を考慮に入れようと言ったのが私の意図でした。
javadba

うわー、あなたの答えは完全に大丈夫でしたが、残念ながら最後の文は間違いなく間違った概念です。ステージ内のパーティション番号がプロセッサの数と等しいことを意味するわけではありませんが、マシンに存在するコアの数に従ってRDDのパーティション数を設定できます。
epcpu 2018

@epcpuこれは特殊なケースでしたが、誤解を招く可能性があるので同意し、削除します。
javadba

26

これは、さまざまな部分をよりよく理解するのに役立ちます。

  • ステージ:タスクのコレクションです。データの異なるサブセット(パーティション)に対して同じプロセスが実行されています。
  • タスク:分散データセットのパーティションでの作業単位を表します。したがって、各ステージでは、タスクの数=パーティションの数、または「パーティションごとにステージごとに1つのタスク」と言います。
  • 各実行者は1つの糸コンテナで実行され、各コンテナは1つのノードに存在します。
  • 各ステージは複数の実行者を利用し、各実行者には複数のvcoreが割り当てられます。
  • 各vcoreは一度に1つのタスクのみを実行できます
  • したがって、どの段階でも、複数のタスクを並行して実行できます。number-of-tasks running = number-of-vcores are used。

2
これは、sparkアーキテクチャに関する非常に役立つ記事
architecture

ポイント番号3を取得できませんでした。私の知る限り、各ノードに複数のエグゼキューターを含めることができるため、ポイント3によると、ノードごとに1つのエグゼキューターのみが存在するはずです。この点を明確にしていただけますか?
Rituparno Behera

@RituparnoBehera各ノードは複数のコンテナーを持つことができるため、複数のSparkエグゼキューターを持つことができます。このリンクをチェックしてください。docs.cloudera.com/runtime/7.0.2/running-spark-applications/...
pedram bashiri

15

私が正しく理解していれば、混乱する2つの(関連する)事柄があります。

1)タスクの内容を決定するものは何ですか?

2)実行するタスクの数は何によって決まりますか?

Sparkのエンジンは、連続したrddsに対する単純な操作を「接着」します。次に例を示します。

rdd1 = sc.textFile( ... )
rdd2 = rdd1.filter( ... )
rdd3 = rdd2.map( ... )
rdd3RowCount = rdd3.count

そのため、rdd3が(緩やかに)計算されると、sparkはrdd1のパーティションごとにタスクを生成し、各タスクはフィルターとマップの両方を行ごとに実行して、rdd3を生成します。

タスクの数は、パーティションの数によって決まります。すべてのRDDには、定義された数のパーティションがあります。HDFSから読み取られるソースRDDの場合(たとえば、sc.textFile(...)を使用)、パーティションの数は、入力形式によって生成される分割の数です。RDDに対する一部の操作では、RDDのパーティション数が異なる場合があります。

rdd2 = rdd1.repartition( 1000 ) will result in rdd2 having 1000 partitions ( regardless of how many partitions rdd1 had ).

別の例は結合です:

rdd3 = rdd1.join( rdd2  , numPartitions = 1000 ) will result in rdd3 having 1000 partitions ( regardless of partitions number of rdd1 and rdd2 ).

(ほとんど)パーティションの数を変更する操作には、たとえば次のような場合にシャッフルが含まれます。

rdd2 = rdd1.repartition( 1000 ) 

実際に何が起こるかは、rdd1の各パーティションのタスクが、rdd2に正確に1000のパーティションを作成するために、次のステージで読み取ることができる最終出力を生成する必要があることです(方法は?ハッシュまたはソート)。このサイドのタスクは、「マップ(サイド)タスク」と呼ばれることもあります。後でrdd2で実行されるタスクは、(rdd2!の)1つのパーティションで動作し、そのパーティションに関連するマップ側の出力を読み取る/組み合わせる方法を理解する必要があります。この側のタスクは、「リデュース(サイド)タスク」と呼ばれることもあります。

2つの質問は関連しています:ステージ内のタスクの数はパーティションの数(連続したrddsに「接着」されたものに共通)であり、RDDのパーティションの数はステージ間で変更できます(パーティションの数をいくつかに指定することにより)たとえば、操作を引き起こすシャッフル)。

ステージの実行が開始されると、そのタスクはタスクスロットを占有できます。並行タスクスロットの数は、numExecutors * ExecutorCoresです。一般に、これらは、異なる非依存ステージからのタスクによって占有される可能性があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.