SPARK数据倾斜,随机数方式

1、现象
spark数据倾斜,有两种表现:
大部分的task,都执行的特别特别快,刷刷刷,就执行完了(你要用client模式,standalone client,yarn client,本地机器主要一执行spark-submit脚本,就会开始打印log),task175 finished;剩下几个task,执行的特别特别慢,前面的task,一般1s可以执行完5个;最后发现1000个task,998,999 task,要执行1个小时,2个小时才能执行完一个task。
出现数据倾斜了,还算好的,因为虽然老牛拉破车一样,非常慢,但是至少还能跑。
运行的时候,其他task都刷刷刷执行完了,也没什么特别的问题;但是有的task,就是会突然间,啪,报了一个OOM,JVM Out Of Memory,内存溢出了,task failed,task lost,resubmitting task。反复执行几次都到了某个task就是跑不通,最后就挂掉。
引用自大佬的原创: https://www.codetd.com/article/5201336
2、原因
基本只可能是因为发生了shuffle操作,在shuffle的过程中,出现了数据倾斜的问题。因为某个,或者某些key对应的数据,远远的高于其他的key。由于shuffle导致的,有几种reduceBykey(),groupByKey(),join等多种,因为数据不均衡
3、解决方式
整体解决方案:
1.数据源聚合---spark任务读取的离线任务百之80是hive,就是在生成hive表数据时候就聚合好,key---values,使得spark读取后每个key对应都是单独的一个值,就不用做reduceByKey,groupByKey等操作
2.过滤引起倾斜的key-----对于业务没有意义的key,在聚合前filter掉
3.两个RDDjoin 引起的倾斜------看数据量,数据量小,将reduce join 转化为Map join算子的操作,通过broadcast小rdd,之后map内部join
4.两个RDD join ------数据量量比较大,sample算子统计引起rdd倾斜的所有key的数据量,将RDD分为两个部分,产生倾斜的rdd和普通的rdd,产生倾斜的rdd,做一个map,对于key加一个N以内的随机前缀,对于join的另外一半rdd,扩容,做flatmap操作,放大N倍,每个key对应0-n-1个前缀,之后新生成的rdd和加了随机前缀的rdd做join,这样就把rdd分散到了多个task区,之后将普通的join结果和这个抽样的倾斜rdd的结果做union就是最终的结果。
5.随机数rdd的方法具体方法:
1、选择一个RDD,要用flatMap,进行扩容,将每条数据,映射为多条数据,每个映射出来的数据,都带了一个n以内的随机数,通常来说会选择10。
2、将另外一个RDD,做普通的map映射操作,每条数据都打上一个10以内的随机数。
3、最后将两个处理后的RDD进行join操作。
6.扩大引起倾斜的算子的并行度-------reduceByKey(rdd,10),groupByKey(rdd,10),增加rdd的并行度
7.双重reduceByKey等聚合函数,第一次执行前做一个map操作,每个kay加一个随机前缀,之后做reduceBykey,再做map去除随机前缀,再做reduceByKey聚合操作
大佬的内容:https://www.codetd.com/article/11560312
数据源聚合和过滤key能直接避免掉数据倾斜。而扩大并行度只能缓和。
查看log日志,一般会报是在你的哪一行代码,导致了OOM异常;或者呢,看log,看看是执行到了第几个stage!!
第一次聚合(局部聚合):对每一个Key值加上一个随机数,执行第一次reduceByKey聚合操作。
第二次聚合(双重聚合):去掉Key值的前缀随机数,执行第二次reduceByKey聚合,最终得到全局聚合的结果。
大佬的博客: https://www.codetd.com/article/5727145
对groupByKey、reduceByKey造成的数据倾斜,有比较好的效果。


/**
		 * 第一步,给每个key打上一个随机数
		 */
		JavaPairRDD<String, Long> mappedClickCategoryIdRDD = clickCategoryIdRDD.mapToPair(

				new PairFunction<Tuple2<Long,Long>, String, Long>() {

					private static final long serialVersionUID = 1L;

					@Override
					public Tuple2<String, Long> call(Tuple2<Long, Long> tuple)
							throws Exception {
						Random random = new Random();
						int prefix = random.nextInt(10);
						return new Tuple2<String, Long>(prefix + "_" + tuple._1, tuple._2);
					}

				});

		/**
		 * 第二步,执行第一轮局部聚合
		 */
		JavaPairRDD<String, Long> firstAggrRDD = mappedClickCategoryIdRDD.reduceByKey(

				new Function2<Long, Long, Long>() {

					private static final long serialVersionUID = 1L;

					@Override
					public Long call(Long v1, Long v2) throws Exception {
						return v1 + v2;
					}

				});

		/**
		 * 第三步,去除掉每个key的前缀
		 */
		JavaPairRDD<Long, Long> restoredRDD = firstAggrRDD.mapToPair(

				new PairFunction<Tuple2<String,Long>, Long, Long>() {

					private static final long serialVersionUID = 1L;

					@Override
					public Tuple2<Long, Long> call(Tuple2<String, Long> tuple)
							throws Exception {
						long categoryId = Long.valueOf(tuple._1.split("_")[1]);  
						return new Tuple2<Long, Long>(categoryId, tuple._2);  
					}

				});

		/**
		 * 第四步,最第二轮全局的聚合
		 */
		JavaPairRDD<Long, Long> clickCategoryId2CountRDD = restoredRDD.reduceByKey(

				new Function2<Long, Long, Long>() {

					private static final long serialVersionUID = 1L;

					@Override
					public Long call(Long v1, Long v2) throws Exception {
						return v1 + v2;
					}

				});

```java
posted @ 2022-08-19 14:10  堕落先锋  阅读(462)  评论(0编辑  收藏  举报