spark优化之数据倾斜

数据倾斜的概念
   有的时候,我们可能会遇到大数据计算中一个最棘手的问题--数据倾斜,此时spark作业的性能会比期望的差的多。数据倾斜调优,就是使用各种技术方案解决不同类型的数据倾斜问题以保证spark作业的性能
   绝大多数task执行的都非常快,但个别task执行极慢,比如,总共有1000个task,997个task都在一分钟内执行完了,但是剩余两三个taks需要一两个小时,这种情况很常见。
   原本能够正常执行的spark作业,某天突然报出OOM(内存溢出)异常,观察异常 栈,是我们写的业务代码造成的,这种情况比较少见。
数据倾斜发生的原理
   数据倾斜的原理很简单:在进行shuffle的时候,必须将各个节点上相同的key拉取到某个节点上的一个task来进行处理,比如按照key进行聚合或join等操作此时如果某个key对应的数据量特别大的话,就会发生数据倾斜。
如何定位导致数据倾斜的代码
   数据倾斜只会发生在shuffle过程中,这里给大家罗列一些常用的并且可能会触发shuffle操作的算子:groupByKey,reduceByKey,join,cogroup,repartition等。出现数据倾斜时,可能是你的使用了这些算子中某一个所导致的。可以使用rdd.sample(false,0.1).countByKey的方式随机抽查出倾斜的数据。
数据倾斜的解决方案
方案一:使用Hive Etl预处理数据
方案使用场景:导致数据倾向性的是Hive表,如果hive表中的数据本身很不均匀。
方案实现思路:此时可以评估一下,是否可以通过hive来进行数据预处理(即通过hive etl 预先对数据按照key进行聚合,或者是预先和其他表进行join),然后在spark作业中针对的数据源就不是原来的hive表了,而是处理后的hive表,此时由于预先进行过聚合或join操作了,那么在spark作业中就不需要使用原先的shuffle类算子执行这类操作了。
方案实现原理:这种方案从根源上解决了数据倾斜,因此彻底避免了在spark中执行shuffle类算子,那么肯定不会有数据倾斜的问题了。但是这里也要提醒下大家,这种方式治标不治本,因为毕竟数据本身就存在不均匀问题,所以hive etl 中进行group by 或 join等shuffle操作时,还是会出现数据倾斜,导致hive etl的速度很慢,我们只是把数据倾斜的发生提前到了hive etl中,避免spark程序发生数据倾斜而已。
方案优点:实现起来简单便捷,效果还非常好,完全避掉了数据倾斜,spark作业性能会大幅度提升。
解决方案二:过滤少量导致数据倾斜的key
方案使用场景:如果发现导致倾斜的key就少数几个,而且对计算本身的影响并不大的话,那么很适合使用这种解决方案,比如99%的key就对应10条数据,但是只有一个key对应了100w万数据,从而导致了数据倾斜。
方案解决思路:如果我们判断那少数几个数据量特别多的key,对作业的执行和计算结果不是特别重要的话,那么可以使用sample算子对rdd进行采样,然后计算出key的数量,取数据量多的key过滤掉即可。
方案实现原理:将导致数据倾斜的key给过滤掉之后,这些key就不对参与计算了,自然不能产生数据倾斜。
方案优缺点:实现简单,而且效果也很好,可能完全避掉数据倾斜,使用场景不多,大多数情况下,导致倾斜的key还是很多,并不算是只有少数几个。
方案三:提高shuffle操作的并行度
方案使用场景:如果我们必须要对数据倾斜迎难而上,那么建议优先使用这些方案,因此这些是处理数据最简单的一种方案。
方案实现思路:在rdd进行shuffle算子时,给shuffle算子传入一个参数,比如reduceByKey(10000)该参数就设置了这个shuffle算子执行时shuffle read task的数量。对于spark sql中的shuffle类语句,比如group by ,join等,需要设置一个参数,即spark.sql.shuffle.partitions,该参数代表了shuffle read task 的并行度,默认值为200,对于很多场景来说都是有点过小。
方案实现原理:增加shuffle read task 的数量,可以让原本分配给一个task的多个key分配给多个task,从而让每个task处理比原来更少的数据。举例来说,如果原本5个key,每个key对应10条数据,这5个key都是分配给一个task的,那么这个task就要处理50条数据,二增加了shuffle read task 以后,每个task就分配到一个key,即每个task就处理10条数据,那么自然每个task的执行时间都会变短了。
方案优点:实现起来比较简单,可以有效的缓解和减轻数据倾斜的影响。
方案缺点:只是缓解了数据倾斜而已,并没有彻底根除了问题,根据实战经验来看,其效果有限。
解决方案四:两阶段聚合(局部聚合+全局聚合)
方案试用场景:对rdd执行reduceByKey等聚合类shuffle算子或在spark sql中使用group by 语句进行了分组聚合是,比较适用这种方案。
方案实现思路:这个方案的核心实现思路就是进行两阶段聚合。第一次是局部聚合,先给每个key都打上一个随机数,比如10以内的随机数,此时原先一样的key就变成不一样的了。
方案实现原理:将原本相同的key通过附加随机前缀的方式,变成多个不同的key,就可以让原本被一个task处理的数据分散到多个task上去做局部聚合,进而解决单个task处理数据量过多的问题。接着去除掉随机前缀,在次进行全局聚合,就可以得到最终的结果。
方案优点:对于聚合类的shuffle操作导致的数据倾斜,效果是非常不错的,通常都可以解决掉数据倾斜,或者至少是大幅度的解除数据倾斜,将spark作业的性能提升数倍以上
方案缺点:仅仅适用于聚合类的shuffle操作,适用范围相对比较窄,如果join类的shuffle操作,还得用其他的解决方案。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值