spark数据倾斜处理实践

本文介绍如何通过Spark Web UI判断数据倾斜,并提供多种解决方案,包括过滤空键、使用广播变量、两阶段聚合及随机前缀与RDD扩容等。

判断是否倾斜

通过Spark Web UI查看运行到了哪个Stage。 主要看最慢的Stage各task里 Shuffle Write Size / Records分配的数据量 相对其他task平均数的比值,来判断是否是数据倾斜。

实践

定位

在这里插入图片描述

如图stage基本在几分钟内、而这个stage运行较长时间,却只有一个task没完成了。这种情况发生倾斜的概率就很大了。我们可以点到具体的stage中看下详情。
在这里插入图片描述
从DAG中我们可以看到有leftOuterJoin算子。所以任务必然有shuffle产生,接着继续看task中Shuffle Write Size / Records分配情况
在这里插入图片描述
我们看到index 为0的这个task分配的数量级比其他task要多出两个。所以这是很明显的数据倾斜。

解决

通过DAG我们能轻松的定位到代码位置,知道是由于letf join造成的后,就可以从这两个表中抽样、或者通过sample抽样,或者查看下topN的key数量。
在这里插入图片描述

这里我们按key排序,发现左边为空的key比重很大。所以在join前加上一个filter过滤掉为空的key

	rdd_letf.filter(f => !f._1.isEmpty)

接下来我们重新提交任务发现刚才的leftOuterJoin算子在两分钟之内就完成了。
当然也不是一切顺利、很快遇到下一个数据倾斜了。这次是inner join左边量级在几亿条、右表八百多万。按之前的方式先看有没有明显key过多情况,发现没有这种情况后。接下来就只好换一种方式了,也就是spark中常用的广播,因为是打表关联小表,所以可以通过map替代join的方式。

    val rdd1 = .. //sc.parallelize(Array(("aa",1),("bb",2),("cc",6)))
    val rdd2 = .. //sc.parallelize(Array(("aa",3),("dd",4),("aa",5)))
    val b_df = sc.broadcast(rdd2.collect).value.toMap 
    // val rdd3 = rdd1.join(rdd2)
    val rdd3 = rdd1.mapPartitions(partitions => partitions.map(r => if(b_df.contains(r._1)) {
   
   (r._1, (r._2, b_df.get(r._1).get))} ))

扩展

常用的解决数据倾斜方法还有提高shuffle操作的并行度,两阶段聚合,采样倾斜key并分拆join操作、使用随机前缀和扩容RDD进行join 等。如果从事数据开发这些基本方法大家都应该需要熟悉。

两阶段聚合(美团样例)

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

方案实现思路:这个方案的核心实现思路就是进行两阶段聚合。第一次是局部聚合,先给每个key都打上一个随机数,比如10以内的随机数,此时原先一样的key就变成不一样的了,比如(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)。然后将各个key的前缀给去掉,就会变成(hello,2)(hello,2),再次进行全局聚合操作,就可以得到最终结果了,比如(hello, 4)。

方案实现原理:将原本相同的key通过附加随机前缀的方式,变成多个不同的key,就可以让原本被一个task处理的数据分散到多个task上去做局部聚合,进而解决单个task处理数据量过多的问题。接着去除掉随机前缀,再次进行全局聚合,就可以得到最终的结果。具体原理见下图。

方案优点:对于聚合类的shuffle操作导致的数据倾斜,效果是非常不错的。通常都可以解决掉数据倾斜,或者至少是大幅度缓解数据倾斜,将Spark作业的性能提升数倍以上。

方案缺点:仅仅适用于聚合类的shuffle操作,适用范围相对较窄。如果是join类的shuffle操作,还得用其他的解决方案。
在这里插入图片描述

// 第一步,给RDD中的每个key都打上一个随机前缀。
JavaPairRDD<String
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值