Spark SQLのブロードキャスト結合は、シャッフル結合よりも高速である必要がありますか?その後、あなたは間違っています。
過去のメモリビッグデータ過去のメモリビッグデータ
この情報は、Workdayのソフトウェア開発エンジニアであるJiannengLiがSparkSummit North America2020で「SparkSQLでのブロードキャスト結合の改善について」トピックを共有したことによるものです。関連するPPTは、必要なSpark AI Summit 2020PPTから入手できます。整理しました。
バックグラウンド
データ分析にApacheSparkを使用する学生は、Sparkでのブロードキャスト結合に精通していると思います。結合の前に、次のように、結合に参加しているワーカーに一方の端で小さなテーブルをブロードキャストします。
Spark、Hadoop、またはHBase関連の記事について時間内に知りたい場合は、WeChatパブリックアカウントiteblog_hadoopに注意してください。
シャッフル結合と比較して、ブロードキャスト結合には次の利点があります。
•大きなテーブルのデータを他のノードにシャッフルしないでください。
•データの
偏りを自然に処理します。Spark、Hadoop、またはHBase関連の記事について時間内に知りたい場合は、WeChatパブリックアカウントiteblog_hadoopに注意してください。
多くの人が、ブロードキャスト結合が適用可能な場合、ブロードキャスト結合はシャッフル結合よりも高速であると結論付けています。しかし、これは本当ですか?
TPC-Hテスト
結論を出す前に、TPC-Hテストを実行して、ブロードキャスト結合がシャッフル結合よりも高速である必要があるかどうかを確認しましょう。試験条件は以下のとおりです。
•データセット10GB;
•クエリ:6000万データラインアイテムテーブル結合1500万注文テーブル
•ドライバー構成:1コア、12 GB
•エグゼキューター構成:1インスタンス、18コア、102 GB
Spark、Hadoop、またはHBase関連の記事について時間内に知りたい場合は、WeChatパブリックアカウントiteblog_hadoopに注意してください。
上記の結果からわかるように、ブロードキャスト結合はシャッフル結合よりも実行が遅くなります。
ブロードキャスト結合メカニズム
上記の結果を理解する前に、ブロードキャスト結合の動作メカニズムを見てみましょう。
Spark、Hadoop、またはHBase関連の記事について時間内に知りたい場合は、WeChatパブリックアカウントiteblog_hadoopに注意してください。
Broadcast Joinを実行する前に、Sparkは最初にExecutor側のデータをDriver側に送信する必要があり、次にDriver側がデータをExecutor側にブロードキャストします。たとえば、大量のデータをブロードキャストする必要がある場合、パラメーターspark.sql.autoBroadcastJoinThresholdを1Gに設定しますが、ドライバー側のメモリ値が500Mに設定されている場合、この状況ではドライバー側にOOMが発生します。以前の分析によると、上記のTPC-Hの結果は次の理由で遅くなります。
•ドライバー側は1500万個のデータを収集する必要があります。
•ドライバー側はハッシュテーブルを作成します。
•ドライバーは作成されたハッシュテーブルをエグゼキューター側に送信します。
•エグゼキューターはハッシュテーブルを逆シリアル化します。
したがって、ブロードキャスト結合の現在の動作メカニズムにより、ブロードキャスト結合が適用可能な場合でも、ブロードキャスト結合は必ずしもシャッフル結合よりも高速であるとは限りません。
過去のビッグデータを覚えておいてください。コードのこの部分に興味がある場合は、最初にorg.apache.spark.sql.executionのexecuteCollectIteratorメソッドを呼び出すBroadcastExchangeExec.scalaクラスの関連コードを参照できます。 .SparkPlanクラスは、主にDriverに送信されたExecutorからデータを削除するためのものであり、getByteArrayRdd()。collect()が内部で呼び出されていることがわかります。
private[spark] def executeCollectIterator(): (Long, Iterator[InternalRow]) = {
val countsAndBytes = getByteArrayRdd().collect()
val total = countsAndBytes.map(_._1).sum
val rows = countsAndBytes.iterator.flatMap(countAndBytes => decodeUnsafeRows(countAndBytes._2))
(total, rows)
}
次に、relationFuture変数の初期化に移ります。
private1 lazy val relationFuture: Future[broadcast.Broadcast[Any]] = {
SQLExecution.withThreadLocalCaptured[broadcast.Broadcast[Any]](
sqlContext.sparkSession, BroadcastExchangeExec.executionContext) {
try {
// 这个地方就是前面说的将数据 Collect 到 Driver 端:
val (numRows, input) = child.executeCollectIterator()
// 这里省去了一部分代码
// Construct the relation.
val relation = mode.transform(input, Some(numRows))
// 这里省去了一部分代码
val beforeBroadcast = System.nanoTime()
longMetric("buildTime") += NANOSECONDS.toMillis(beforeBroadcast - beforeBuild)
// Broadcast the relation
// 这个地方就是前面说的需要先 broadcast 数据到 Executor 端
val broadcasted = sparkContext.broadcast(relation)
longMetric("broadcastTime") += NANOSECONDS.toMillis(
System.nanoTime() - beforeBroadcast)
val executionId = sparkContext.getLocalProperty(SQLExecution.EXECUTION_ID_KEY)
SQLMetrics.postDriverMetricUpdates(sparkContext, executionId, metrics.values.toSeq)
promise.trySuccess(broadcasted)
broadcasted
} catch {
// 这里省去了一部分代码
}
}
}
ブロードキャスト結合のパフォーマンスを向上させる
上記の分析を考慮すると、データをドライバー側に収集するのではなく、エグゼキューター側の間で直接データを交換することはできますか?これは、Workdayのエンジニアリングチームによってもたらされたエグゼキュータ側のブロードキャストです。この作業は、SPARK-17556で見ることができます。エグゼキュータ側でのブロードキャストの動作原理を見てみましょう。
•エグゼキュータは、Joinに必要なデータを他のエグゼキュータにブロードキャストします。
•ドライバは、エグゼキュータのブロック情報の記録のみを担当するため、他のエグゼキュータは、どのエグゼキュータからブロックを取得できるかを知ることができます。
具体的なプロセスは次のとおりです。
Spark、Hadoop、またはHBase関連の記事について時間内に知りたい場合は、WeChatパブリックアカウントiteblog_hadoopに注意してください。
試験結果
Workdayエンジニアは、次の3つのテストシナリオをテストしました。
•データ量は同じままで、異なるコアのパフォーマンスは個別にテストされます。
•パフォーマンスを測定するためにラインアイテムテーブルのサイズが異なります。
•注文テーブルのサイズを増やした
結果は次のとおりです。
Spark、Hadoop、またはHBase関連の記事について時間内に知りたい場合は、WeChatパブリックアカウントiteblog_hadoopに注意してください。
Spark、Hadoop、またはHBase関連の記事について時間内に知りたい場合は、WeChatパブリックアカウントiteblog_hadoopに注意してください。
Spark、Hadoop、またはHBase関連の記事について時間内に知りたい場合は、WeChatパブリックアカウントiteblog_hadoopに注意してください。要約:
•同じ量のデータの場合、コアの数が比較的多い場合はシャッフル結合が有利です。
•非ブロードキャストテーブルのデータ量がどんどん大きく
なっている場合は、ブロードキャスト結合が有利です。•それがブロードキャストテーブルのデータ量については、ドライバ側のブロードキャストは結果を生成できず、エグゼキュータのブロードキャスト結合は比較的高速です。
上記の結論によると、ブロードキャストは必ずしもシャッフルよりも高速であるとは限らないことを誰もが知っている必要があります。さらに、エグゼキュータ側のブロードキャスト機能が2016年9月に言及されました。最新のApache Spark 3.0.0の時点では、この機能はメインブランチにマージされていません。これが必要な場合は、自分でマージできます。