企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
**1. 对数据进行 ETL 预处理** 使用场景: (1)hive 中文件大小不均匀,有的大有的小。spark在读取大文件时会对大文件按照block快进行切分,小文件不会切分。如果不进行预处理,那么小文件处理速度快,大文件处理慢、资源没有得到充分利用,可以先对hive数据进行清洗、去重、重新分区等操作来将原本不均匀的数据重新均匀的存放在多个文件中。以简化后面依赖此数据源的任务。 (2)hive 中 key分布不均匀,可以将shuffle类操作先进行处理。处理完毕之后,spark应用不必进行重复的shuffle,直接用处理后的结果就可以。在频繁调用 spark 作业并且有实效要求的场景中,如果今天作业要用到昨天数据的聚合数据,可以每天进行一次预处理,将数据聚合好,从而保证今天作业的实效要求。 <br/> **2. 过滤少数导致倾斜的 key** 使用场景: (1)倾斜 key 没有意义时,比如存在很多 key是`-`(`-`在我们系统代表空)的记录,那么就可以直接filter掉来解决`-`带来的数据倾斜。 (2)倾斜 key 是有意义的,那么就需要单独拎出来进行单独处理。 <br/> **3. 提高 shuffle 操作的并行度** 使用场景:同一个 task 被分配了多个倾斜的 key。试图增加 shuffle read task的数量,可以让原本分配给一个 task 的多个 key 分配给多个 task,从而让每个 task处理比原来更少的数据。实现起来比较简单,可以有效缓解和减轻数据倾斜的影响,原理如下图 ![](https://img.kancloud.cn/54/58/5458ae27d34d57c3aa6354838945177c_832x371.png) 具体操作是将shuffle算子,比如groupByKey、countByKey、reduceByKey。在调用的时候传入进去一个参数,一个数字。那个数字就代表了那个 shuffle 操作的 reduce 端的并行度。那么在进行 shuffle 操作的时候,就会对应着创建指定数量的 reduce task。 <br/> **4. 两阶段聚合(局部聚合+全局聚合)** 使用场景:对 RDD 执行 reduceByKey 等聚合类 shuffle 算子或者在 Spark SQL中使用group by语句进行分组聚合时,比较适用这种方案。如果是join类的shuffle操作,还得用其他的解决方案。 <br/> 实现方式:将原本相同的key通过附加随机前缀的方式,变成多个不同的key,就可以让原本被一个 task 处理的数据分散到多个 task 上去做局部聚合,进而解决单个 task 处理数据量过多的问题。接着去除掉随机前缀,再次进行全局聚合,就可以得到最终的结果。如下图所示。 ![](https://img.kancloud.cn/fe/66/fe66feda38200750b1b75fd8f6a87097_1014x418.png) <br/> **5. 将 reduce join 转为 map join** 使用场景:join 类操作,存在小表 join 大表的场景。可以将小表进行广播从而避免shuffle。 <br/> **6. 采样倾斜 key 并分拆 join 操作** 使用场景:适用于 join 类操作中,由于相同 key 过大占内存,不能使用第 5个方案,但倾斜 key 的种数不是很多的场景。<br/> 实现方式: 第(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 结果。 <br/> 具体原理见下图: ![](https://img.kancloud.cn/e9/46/e946774119b41b76ba67bd17ba822fff_787x750.png) <br/> **7. 使用随机前缀和扩容 RDD 进行 join** 使用场景:如果在进行 join 操作时,RDD 中有大量的 key 导致数据倾斜。同第 6 个方案,不同的是它不需要对原先 rdd 进行倾斜 key 过滤,将原来 rdd形成含倾斜 key的rdd,与不含倾斜key的rdd。直接对整个原本的rdd的key一边进行加随机数,另一边进行相应倍数的扩容。而这一种方案是针对有大量倾斜 key的情况,没法将部分key拆分出来进行单独处理,因此只能对整个RDD进行数据扩容,对内存资源要求很高。