スパーク傾いデータを解決するためのいくつかの一般的な方法

データスキューが最も困難な課題の一つを計算するためのビッグデータで、データスキュー後、スパークジョブのパフォーマンスが予想よりもはるかに悪くなります。データスキューを調整することは保証されたデータ・スキューの問題の様々な異なる種類を使用して、仕事のパフォーマンスアートのソリューションをスパークです。

データスキューの最初に、原則

ジョブスパークに従って操作をシャッフルしますジョブの複数に、その内部アクション操作にジョブを複数の各内部ステージに分割され、各ステージに割り当てられたタスクの複数のタスクを実行します。各タスクは、データ処理のパーティションを受け取ることになります。

同じステージ内のタスクは、異なるステージ依存性を有するシリアル処理で、データの並列処理です。この処理により機構に、2つの段階、それぞれSTAGE0とステージ1があるスパークジョブに仕事をするとし、その後、ステージ1は場所を取ることができSTAGE0プロセスが終了を待たなければなりません。コンピューティングタスクのためのn個のSTAGE0タスクの内部分布は、データ・パーティションを受信する必要があるタスクが大きすぎる場合、それは1時間かけていない実行、N-1時間半のタスクの実行内に残りは終了し、中など、この最後のタスクの実行には、次のステージに進むために終了します。なぜならステージ現象内部に大量のデータを受信するために、このタスクは、データ・スキューです。

図は一例である:こんにちは残りの二つに対処するために、同じタスクにマッピングされたデータに鍵7相当だけタスクデータを処理しました。

1503160-390346e5473a42fa.png
データスキュー

第二に、データの偏り現象が発生します

1は、タスクの実行の大半は非常に高速だったが、個々のタスクは非常に遅く実行します。1分以内に終了番目例えば、総タスク1000と、タスク997が実行され、残りの二十から三タスクは12時間に有しています。この状況は非常に一般的です。

2、スパークは、ジョブの正常な実行を持っていた、ある日突然異常なスタックを観察し、異常(メモリのうち)OOMを報告し、我々は、ビジネス・コードが原因書きます。これは比較的まれです。

第三に、どのように斜めの位置データコード

数据倾斜只会发生在 shuffle 过程中。常用并且可能会触发 shuffle 操作的算子有:distinct,groupByKey,reduceByKey,aggregateByKey,join,cogroup,repartition 等。出现数据倾斜,很有可能就是使用了这些算子中的某一个导致的。

如果我们是 yarn-client 模式提交,我们可以在本地直接查看 log,在 log 中定位到当前运行到了哪个 stage;如果用的 yarn-cluster 模式提交的话,我们可以通过 spark web UI 来查看当前运行到了哪个 stage。无论用的哪种模式我们都可以在 spark web UI 上面查看到当前这个 stage 的各个 task 的数据量和运行时间,从而能够进一步确定是不是 task 的数据分配不均导致的数据倾斜。

当确定了发生数据倾斜的 stage 后,我们可以找出会触发 shuffle 的算子,推算出发生倾斜的那个 stage 对应代码。触发 shuffle 操作的除了上面提到的那些算子外,还要注意使用 spark sql 的某些 sql 语句,比如 group by 等。

四,解决方法

解决数据倾斜的思路就是保证每个 stage 内部的 task 领取的数据足够均匀。一个是想办法让数据源在 Spark 内部计算粒度的这个维度上划分足够均匀,如果做不到这个,就要相办法将读取的数据源进行加工,尽量保证均匀。大致有以下几种方案。

1,聚合源数据和过滤导致倾斜的 key

a,聚合源数据

假设我们的某个 Spark 作业的数据源是每天 ETL 存储到 Hive 中的数据,这些数据主要是电商平台每天用户的操作日志。Spark 作业中分析的粒度是 session,那么我们可以在往 Hive 中写数据的时候就保证每条数据对应一个 session 的所有信息,也就是以 session 为粒度的将数据写入到 Hive 中。

这样我们可以保证一点,我们 Spark 作业中就没有必要做一些 groupByKey + map 的操作了,可以直接对每个 key 的 value 进行 map 操作,计算我们需要的数据。省去了 shuffle 操作,避免了 shuffle 时的数据倾斜。

但是,当我们 Spark 作业中分析粒度不止一个粒度,比如除了 session 这个粒度外,还有 date 的粒度,userId 的粒度等等。这时候是无法保证这些所有粒度的数据都能聚合到一条数据上的。这时候我们可以做个妥协,选择一个相对比较大的粒度,进行聚合数据。比如我们按照原来的存储方式可能有 100W 条数据,但按照某个粒度,比如 date 这个粒度,进行聚合后存储,这样的话我们的数据可以降到 50W 条,可以做到减轻数据倾斜的现象。

b,过滤导致倾斜的 key

比如说我们的 Hive 中数据,共有 100W 个 key,其中有 5 个 key 对应的数据量非常的大,可能有几十万条数据(这种情况在电商平台上发生恶意刷单时候会出现),其它的 key 对应数据量都只有几十。如果我们业务上面能够接受这 5 个 key 对应的数据可以舍弃。这种情况下我们可以在用 sql 从 Hive 中取数据时过滤掉这个 5 个 key。从而避免了数据倾斜。

2,shuffle 操作提高 reduce 端的并行度

Spark 在做 shuffle 操作时,默认使用的是 HashPartitioner 对数据进行分区。如果 reduce 端的并行度设置的不合适,很可能造成大量不同的 key 被分配到同一个 task 上去,造成某个 task 上处理的数据量大于其他 task,造成数据倾斜。

如果调整 reduce 端的并行度,可以让 reduce 端的每个 task 处理的数据减少,从而缓解数据倾斜。

设置方法:在对 RDD 执行 shuffle 算子时,给 shuffle 算子传入一个参数,比如 reduceByKey(1000) ,该参数就设置了这个 shuffle 算子执行时 shuffle read task 的数量。对于 Spark SQL 中的 shuffle 类语句,比如 group by、join 等,需要设置一个参数,即 spark.sql.shuffle.partitions ,该参数代表了 shuffle read task 的并行度,该值默认是 200 ,对于很多场景来说都有点过小。

3,使用随机 key 进行双重聚合

在 Spark 中使用 groupByKey 和 reduceByKey 这两个算子会进行 shuffle 操作。这时候如果 map 端的文件每个 key 的数据量偏差很大,很容易会造成数据倾斜。

我们可以先对需要操作的数据中的 key 拼接上随机数进行打散分组,这样原来是一个 key 的数据可能会被分到多个 key 上,然后进行一次聚合,聚合完之后将原来拼在 key 上的随机数去掉,再进行聚合,这样对数据倾斜会有比较好的效果。

具体可以看下图:

1503160-7fbb8078ea9c2411.png
随机 key 双重聚合

这种方案对 RDD 执行 reduceByKey 等聚合类 shuffle 算子或者在 Spark SQL 中使用 group by 语句进行分组聚合时,比较适用这种方案。

4, 将 reduce-side join 转换成 map-side join

两个 RDD 在进行 join 时会有 shuffle 操作,如果每个 key 对应的数据分布不均匀也会有数据倾斜发生。

这种情况下,如果两个 RDD 中某个 RDD 的数据量不大,可以将该 RDD 的数据提取出来,然后做成广播变量,将数据量大的那个 RDD 做 map 算子操作,然后在 map 算子内和广播变量进行 join,这样可以避免了 join 过程中的 shuffle,也就避免了 shuffle 过程中可能会出现的数据倾斜现象。

5,采样倾斜 key 并拆分 join 操作

当碰到这种情况:两个 RDD 进行 join 的时候,其中某个 RDD 中少数的几个 key 对应的数据量很大,导致了数据倾斜,而另外一个 RDD 数据相对分布均匀。这时候我们可以采用这种方法。

1,对包含少数几个数据量过大的 key 的那个 RDD,通过 sample 算子采样出一份样本来,然后统计一下每个 key 的数量,计算出来数据量最大的是哪几个 key。

2,然后将这几个 key 对应的数据从原来的 RDD 中拆分出来,形成一个单独的 RDD,并给每个 key 都打上 n 以内的随机数作为前缀,而不会导致倾斜的大部分 key 形成另外一个 RDD。

3,接着将需要 join 的另一个 RDD,也过滤出来那几个倾斜 key 对应的数据并形成一个单独的 RDD,将每条数据膨胀成 n 条数据,这 n 条数据都按顺序附加一个 0~n 的前缀,不会导致倾斜的大部分 key 也形成另外一个 RDD。

4,再将附加了随机前缀的独立 RDD 与另一个膨胀 n 倍的独立 RDD 进行 join,此时就可以将原先相同的 key 打散成 n 份,分散到多个 task 中去进行 join 了。

5, 而另外两个普通的 RDD 就照常 join 即可。 最后将两次 join 的结果使用 union 算子合并起来即可,就是最终的 join 结果。

具体可以看下图:

1503160-a79bd320f6641de7.png
采样倾斜 key 分别 join

6,使用随机前缀和扩容 RDD 进行 join

結合操作中に、RDDは、キーデータスキューが多数につながる場合には、スピンオフの鍵は、あなたがこのプログラムを取ることができ、この時点で、意味を成しません。

プログラムの基本的な考え方を達成し、類似した上で、最初の大きさであるように、複数のキーマッピングデータとして、データスキューRDDの原因を見つけ、データのRDDの分布を確認してください。その後、我々は接頭辞nの内ランダムでマークされるRDDデータ転送をしました。RDDは、拡張のために、n個のデータ拡張にデータを転送しなかった、他には、拡張を順次0〜n個のデータのプレフィックスのそれぞれをマークしながら。二人はその後だったRDDが参加します。

1はRDDのためにあるので、一緒に1と少ないサンプリングプロセス、よりこのプログラムは、唯一のキーデータスキューの非常に小さな数が発生し、これらのキーのための特別な処理が必要となります。そして、このプログラムは、キーデータスキューの多くはRDDのために発生し、サンプリングのこの時点での必要はありません。

ます。https://www.jianshu.com/p/768d9e8536c3で再現

おすすめ

転載: blog.csdn.net/weixin_34183910/article/details/91073741
おすすめ