Sparkパフォーマンス最適化ガイド-データスキューの一般的なアイデア

Sparkがデータを処理するとき、データスキューの問題がよく発生します。データスキューを軽減する方法は、Sparkの計算効率を改善するために非常に明白です。

データチルトが発生したときの現象

ほとんどのタスクは非常に高速に実行されますが、個々のタスクは非常に低速です。たとえば、合計1,000個のタスクがあり、997個のタスクが1分以内に実行されますが、残りの2つまたは3つのタスクは1時間または2時間かかります。この状況は非常に一般的です。

正常に実行できたSparkジョブが突然OOM(メモリオーバーフロー)例外を報告した例外スタックの観察は、私たちが記述したビジネスコードが原因で発生しました。この状況は比較的まれです。

データスキューの原則

データスキューの原理は非常に単純です。シャッフルを実行する場合、各ノードの同じキーをノードのタスクにプルして、キーに応じた集計や結合などの処理を行う必要があります。このとき、キーに対応するデータ量が特に多い場合、データスキューが発生します。たとえば、ほとんどのキーは10個のデータに対応しますが、個々のキーは100万個のデータに対応します。ほとんどのタスクは10個のデータにしか割り当てられず、1秒で実行されますが、個々のタスクは100万個のデータに割り当てられます。データは1〜2時間実行する必要があります。したがって、Sparkジョブ全体の実行中の進行状況は、実行時間が最も長いタスクによって決まります。

そのため、データが偏っている場合、Sparkジョブの実行速度は非常に遅くなり、タスクで処理される大量のデータが原因でメモリオーバーフローが発生する可能性さえあります。

次の図は非常に明確な例です。キーhelloは3つのノードで合計7個のデータに対応し、これらのデータは同じタスクに処理のために取り込まれます。 1つのデータなので、他の2つのタスクは1つのデータを処理するだけで済みます。このとき、最初のタスクの実行時間は、他の2つのタスクの実行時間の7倍になり、ステージ全体の実行速度も、最も遅い実行中のタスクによって決まります。

ここに画像の説明を挿入

データスキューソリューション

1.傾きを引き起こすいくつかのキーをフィルタリングします

スキームに適用可能なシナリオ:傾斜を引き起こすキーがわずかしかなく、計算自体への影響が大きくない場合、このスキームは非常に適しています。たとえば、キーの99%が10個のデータに対応しますが、100万個のデータに対応するキーは1つだけなので、データが歪んでしまいます。

ソリューション実装のアイデア:大量のデータを含む少数のキーを判断し、ジョブの実行と計算結果にとって特に重要ではない場合は、単純に少数のキーを除外します。たとえば、Spark SQLでは、where句を使用してこれらのキーをフィルターで除外したり、Spark CoreのRDDでフィルター演算子を実行してこれらのキーをフィルターで除外したりできます。データ量が最も多いキーを動的に決定し、ジョブが実行されるたびにフィルタリングする必要がある場合は、サンプル演算子を使用してRDDをサンプリングし、各キーの数を計算できます。データ量が最も多いキーはフィルターで除外されます。ええ

ソリューション実装の原則:データスキューの原因となるキーをフィルタリングした後、これらのキーは計算に参加せず、データスキューを生成することは当然不可能です。

ソリューションの利点:実装は単純で、効果も非常に良好で、データの傾きを完全に回避できます。

スキームの短所:適用可能なシナリオは多くありませんが、ほとんどの場合、傾斜を引き起こすキーはいくつかだけではなく、まだ多くあります。

プログラムの実務経験:データの傾きを解決するために、このプログラムもプロジェクトに採用しています。実行中にSparkジョブが突然OOMであることがわかりました。トレースした後、Hiveテーブルのキーにその日の異常なデータがあり、データ量が突然増加していることがわかりました。したがって、サンプリングは各実行の前に実行され、サンプル内のデータ量が最大のキーを計算した後、それらのキーはプログラムで直接フィルタリングされます。

2.シャッフル操作の並列性を改善する

シナリオの適用シナリオ:データスキューの問題に直面する必要がある場合は、最初にこのスキームを使用することをお勧めします。これがデータスキューを処理する最も簡単な方法だからです。

ソリューション実装のアイデア:RDDでシャッフルオペレーターを実行するときに、reduceByKey(1000)などのパラメーターをシャッフルオペレーターに渡します。このパラメーターは、シャッフルオペレーターが実行されるときのシャッフル読み取りタスクの数を設定します。group by、joinなどのSpark SQLのシャッフルSQLステートメントの場合、パラメーターを設定する必要があります。つまり、spark.sql.shuffle.partitionsは、シャッフル読み取りタスクの並列処理を表します。多くのシナリオで、デフォルト値は200です。少し小さすぎます。

ソリューション実装の原則:シャッフル読み取りタスクの数を増やすと、元々タスクに割り当てられていた複数のキーを複数のタスクに割り当てることができるため、各タスクが処理するデータが元のタスクより少なくなります。たとえば、元々5つのキーがあり、各キーが10個のデータに対応し、これらの5個のキーがすべてタスクに割り当てられている場合、このタスクは50個のデータを処理します。シャッフル読み出しタスクを追加すると、各タスクにキーが割り当てられます。つまり、各タスクは10データを処理するため、当然、各タスクの実行時間は短くなります。具体的な原理を下図に示します。

ソリューションの利点:実装は比較的簡単で、データスキューの影響を効果的に軽減および軽減できます。

ソリューションの短所:データスキューが軽減されるだけで、問題が完全に解消されるわけではありません。実際の経験によれば、その効果は限られています。

ソリューションの実際の経験:このソリューションは通常、データの傾きを完全に解決することはできません。100万のデータに対応するキーなどの極端な状況がある場合、タスク数がどれだけ増加しても、これは100万のデータのキーに対応するためです。確かに、処理するタスクに割り当てられているため、データスキューが発生する運命にあります。したがって、この種のソリューションは、データスキューが見つかったときに最初に試す方法、データスキューを緩和する簡単な口の方法、または他のソリューションと組み合わせて使用​​する方法と言えるでしょう。
ここに画像の説明を挿入

3. 2ステージ集約(ローカル集約+グローバル集約)

スキームに適用可能なシナリオ:このスキームは、Spark SQLのgroup byステートメントを使用して、RDDまたはグループでreduceByKeyなどの集計シャッフル演算子を実行する場合により適しています。

ソリューション実現のアイデア:このソリューションのコア実現のアイデアは、2段階の集約を行うことです。最初はローカル集約で、最初に各キーに乱数(10以内の乱数など)を割り当てます。その後、元のキーは(hello、1)(hello、1)などのように異なります(hello、1)(hello、1)、(1_hello、1)(1_hello、1)(2_hello、1)(2_hello、1)になります。次に、乱数を追加した後、データに対してreduceByKeyなどの集計操作を実行し、ローカル集計を実行すると、ローカル集計結果は(1_hello、2)(2_hello、2)になります。次に、各キーのプレフィックスを削除すると、それは(hello、2)(hello、2)になり、グローバル集計操作を再度実行すると、(hello、4)などの最終結果を取得できます。

ソリューションの実装原理:元の同じキーがランダムプレフィックスを追加することで複数の異なるキーに変更されるため、タスクによって最初に処理されたデータをローカル集約のために複数のタスクに分散し、単一のタスクでデータを処理できます。問題が多すぎます。次に、ランダムなプレフィックスを削除し、グローバル集約を再度実行して、最終結果を取得します。具体的な原理を下図に示します。

ソリューションの利点:集約クラスのシャッフル操作によって引き起こされるデータスキューの影響は非常に良好です。通常、データスキューを解決するか、少なくともデータスキューを大幅に軽減し、Spark操作のパフォーマンスを数倍以上改善できます。

ソリューションの短所:これは、集約クラスのシャッフル操作にのみ適用可能であり、適用範囲は比較的狭いです。結合タイプのシャッフル操作の場合は、他のソリューションを使用する必要があります。
ここに画像の説明を挿入

4.縮小結合をマップ結合に変換する

シナリオに適用可能なシナリオ:RDDで結合操作を使用する場合、またはSpark SQLで結合ステートメントを使用する場合、結合操作でのRDDまたはテーブルのデータ量が比較的少ない(数百Mまたは1 Gまたは2 Gなど)場合、より適切ですこのプログラム。

ソリューション実装のアイデア:接続操作に結合演算子を使用する代わりに、ブロードキャスト変数とマップ演算子を使用して結合操作を実行し、シャッフルクラスの操作を完全に回避し、データチルトの発生と発生を完全に回避します。小さいRDD内のデータは、収集演算子を介してドライバー側のメモリに直接プルされ、そのためのブロードキャスト変数が作成され、マップクラス演算子が別のRDDで実行されます。小さいRDDのデータの全量を取得し、接続キーに従って現在のRDDの各データを比較します。接続キーが同じである場合は、2つのRDDのデータを必要な方法で接続します。

ソリューション実装の原則:通常の結合はシャッフルプロセスを通過します。シャッフルすると、同じキーのデータをシャッフル読み取りタスクにプルしてから結合するのと同じことになります。これがリデュース結合です。ただし、RDDが比較的小さい場合は、ブロードキャストの小さなRDDフルデータ+マップ演算子を使用して、結合と同じ効果、つまりマップ結合を実現できます。その後、シャッフル操作は発生せず、データチルトは発生しません。 。具体的な原理を下図に示します。

このスキームの利点:シャッフルがまったく発生せず、データチルトがまったく発生しないため、結合操作によって引き起こされるデータチルトは非常に効果的です。

スキームの短所:このスキームは大きなテーブルと小さなテーブルにのみ適用できるため、適用できるシナリオは少なくなります。結局、より多くのメモリリソースを消費する小さなテーブルをブロードキャストする必要があり、ドライバと各エグゼキュータのメモリには、小さなRDDの全量のデータが含まれます。ブロードキャストするRDDデータが10Gを超えるなど、比較的大きい場合、メモリオーバーフローが発生する可能性があります。したがって、両方が大きなテーブルである場合には適していません。
ここに画像の説明を挿入

5.チルトキーのサンプリングと結合操作の分割

シナリオの適用シナリオ:2つのRDD / Hiveテーブルが結合されている場合、データ量が比較的大きく、「ソリューション5」を採用できない場合は、2つのRDD / Hiveテーブルのキー分布を確認できます。1つのRDD /ハイブテーブル内のいくつかのキーのデータ量が大きすぎるためにデータが歪んでいて、他のRDD /ハイブテーブル内のすべてのキーが均等に分散されている場合、このソリューションがより適切です。の。

ソリューション実装のアイデア:*大量のデータを持ついくつかのキーを含むRDDの場合、サンプルオペレーターを介してサンプルをサンプリングし、各キーの数を数えて、どれが最大のデータ量を持っているかを計算します。キー。*次に、これらのキーに対応するデータを元のRDDから分割して個別のRDDを作成し、傾斜したキーのほとんどを形成せずに、各キーの前にn内の乱数を付けます別のRDD。*次に、結合する必要のある別のRDDと、いくつかの傾斜キーに対応するデータも除外されて個別のRDDが形成され、各データはn個のデータに展開され、n個のデータには0〜nが順に追加されますプレフィックスによって、傾斜したキーのほとんどが別のRDDを形成することはありません。*次に、ランダムなプレフィックスを使用して独立RDDを結合し、n倍に拡張して別の独立RDDを結合します。このとき、元の同じキーをn部に分割し、複数のタスクに分散して結合できます。*他の2つの通常のRDDは通常どおりに結合できます。*最後に、2つの結合の結果は、最終的な結合結果である共用体演算子を使用して結合できます。

ソリューションの実装原理:結合によって引き起こされるデータの傾きの場合、少数のキーだけが傾きを引き起こす場合、いくつかのキーを独立したRDDに分割し、ランダムなプレフィックスを追加してn個の共有に分割して結合できます。キーに対応するデータは、いくつかのタスクに集中しませんが、結合するために複数のタスクに分散されます。具体的な原理を下図に示します。

ソリューションの利点:結合によって引き起こされるデータの傾きの場合、少数のキーだけが傾きを引き起こす場合、この方法を使用して、最も効果的な結合方法でキーを分割できます。さらに、いくつかの傾斜キーに対応するデータをn回展開するだけでよく、データ全体を展開する必要はありません。メモリーを使いすぎないようにしてください。

ソリューションの短所:ティルトの原因となるキーが特に多い場合、たとえば数千のキーがデータのティルトを引き起こす場合、この方法は適していません。
ここに画像の説明を挿入

6.ランダムプレフィックスと拡張RDDを使用して参加する

シナリオに適用可能なシナリオ:結合操作中にデータのスキューを引き起こすキーがRDDに多数ある場合、キーを分割しても意味がありません。現時点では、最後のソリューションのみを使用して問題を解決できます。

ソリューションの実装のアイデア:*ソリューションの実装のアイデアは基本的に「ソリューション6」に似ています。最初に、RDD / Hiveテーブルのデータ分布を確認して、データの傾きを引き起こしたRDD / Hiveテーブルを見つけます。たとえば、複数のキーは10,000以上のデータ。*次に、RDDの各データには、n内のランダムなプレフィックスがプレフィックスされます。*同時に、別の通常のRDDを展開し、各データをn個のデータに展開します。展開された各データには、0からnまでのプレフィックスが順番に付けられます。*最後に、処理された2つのRDDを結合します。

ソリューション実装の原則:元の同じキーをランダムなプレフィックスを追加して別のキーに変更し、これらの処理された「異なるキー」を複数のタスクに分散して処理させることができます。キー。このソリューションと「ソリューション6」の違いは、最後のソリューションが傾いたいくつかのキーに対応するデータに対してのみ特別な処理を実行しようとすることです。処理プロセスはRDDを拡張する必要があるため、前のソリューションはRDDのメモリを拡張します。占有率は大きくありません。この種の解決策は、多数の歪んだキーの場合に対応します。いくつかのキーを分割して個別の処理を行うことは不可能であるため、RDD全体のみをデータで拡張でき、大量のメモリリソースが必要になります。

スキームの利点:基本的に、結合タイプのデータティルトを処理でき、その効果は比較的大きく、パフォーマンスの向上効果は非常に良好です。

スキームの欠点:このスキームは、データスキューを完全に回避するのではなく、データスキューを緩和するためのものです。さらに、RDD全体を拡張する必要があるため、高いメモリリソースが必要になります。

プログラムの実務経験:データ要件を開発する際、結合がデータの歪みを引き起こすことが発見されました。最適化前のジョブの実行時間は約60分です。このスキームを使用して最適化した後、実行時間は約10分に短縮され、パフォーマンスが6倍向上します。

19件の元の記事を公開 賞賛21件 訪問913件

おすすめ

転載: blog.csdn.net/weixin_42134034/article/details/105623070