使用随机key实现双重聚合
1、原理
把key前面都加上个随机数,使得key分散,让key跑到不同的task上面去!
然后再经过反向映射map算子再把前缀去掉,再去计算
双重聚合就是聚合两遍
2、使用场景
(1)groupByKey
(2)reduceByKey
比较适合使用这种方式;
join,咱们通常不会这样来做,后面会讲三种,针对不同的join造成的数据倾斜的问题的解决方案。
第一轮聚合的时候,对key进行打散,将原先一样的key,变成不一样的key,相当于是将每个key分为多组;
先针对多个组,进行key的局部聚合;接着,再去除掉每个key的前缀,然后对所有的key,进行全局的聚合。
对groupByKey、reduceByKey造成的数据倾斜,有比较好的效果。
如果说,之前的第一、第二、第三种方案,都没法解决数据倾斜的问题,那么就只能依靠这一种方式了。
1751行
第一步,使用随机key实现双重聚合
第二步,执行第一轮局部聚合
第三步,去除掉每个key的前缀
第四步,最后第二轮全局的聚合
B,数据倾斜解决方案 将reduce join转换为map join
普通的join,那么肯定是要走shuffle;那么,所以既然是走shuffle,那么普通的join,
就肯定是走的是reduce join。
先将所有相同的key,对应的values,汇聚到一个task中,然后再进行join
将reduce join转换为map join,现在不是两个RDD JOIN了,而是一个RDD做成broadcast出来的普通变量
map操作,MapPartitions操作
reduce join转换为map join,适合在什么样的情况下,可以来使用???
如果两个RDD要进行join,其中一个RDD是比较小的。一个RDD是100万数据,一个RDD是1万数据。
(一个RDD是1亿数据,一个RDD是100万数据)
其中一个RDD必须是比较小的,broadcast出去那个小RDD的数据以后,就会在每个executor的
block manager中都驻留一份。要确保你的内存足够存放那个小RDD中的数据
这种方式下,根本不会发生shuffle操作,肯定也不会发生数据倾斜;
从根本上杜绝了join操作可能导致的数据倾斜的问题;
对于join中有数据倾斜的情况,大家尽量第一时间先考虑这种方式,效果非常好;
如果某个RDD比较小的情况下。
注意:----> 在项目中,我们在按时间抽取出每天没小时的session 的索引时,用到了广播变量,
将广播到各个excutor 中
不适合的情况???
两个RDD都比较大,那么这个时候,你去将其中一个RDD做成broadcast,就很笨拙了。
很可能导致内存不足。最终导致内存溢出,程序挂掉。
而且其中某些key(或者是某个key),还发生了数据倾斜;此时可以采用最后两种方式。
564行
reduce join转换为map join
对于join这种操作,不光是考虑数据倾斜的问题;即使是没有数据倾斜问题,也完全可以优先考虑,
用我们讲的这种高级的reduce join转map join的技术,不要用普通的join,去通过shuffle,
进行数据的join;完全可以通过简单的map,使用map join的方式,牺牲一点内存资源;
在可行的情况下,优先这么使用。
不走shuffle,直接走map,是不是性能也会高很多?这是肯定的。
C,数据倾斜解决方案 sample采样倾斜key单独进行join
采样出来倾斜的KEY然后进行两次JOIN,采样10%计算每个key出现的次数,按照出现次数进行排序,
排序后拿到最多的一个或几个key,拿到可能会导致数据倾斜的一个或几个key
然后我们把原始RDD拆分为产生倾斜的key的RDD和普通的key的RDD,然后分别去和其他表进行JOIN
然后合并两个JOIN后的表!!!
这个方案的实现思路,跟大家解析一下:其实关键之处在于,将发生数据倾斜的key,单独拉出来,
放到一个RDD中去;就用这个原本会倾斜的key RDD跟其他RDD,单独去join一下,这个时候,
key对应的数据,可能就会分散到多个task中去进行join操作。
就不至于说是,这个key跟之前其他的key混合在一个RDD中时,肯定是会导致一个key对应的所有数据,
都到一个task中去,就会导致数据倾斜。
这种方案什么时候适合使用???
优先对于join,肯定是希望能够采用上一讲讲的,reduce join转换map join。两个RDD数据都比较大,
那么就不要那么搞了。
针对你的RDD的数据,你可以自己把它转换成一个中间表,或者是直接用countByKey()的方式,
你可以看一下这个RDD各个key对应的数据量;此时如果你发现整个RDD就一个,或者少数几个key,
是对应的数据量特别多;尽量建议,比如就是一个key对应的数据量特别多。
此时可以采用咱们的这种方案,单拉出来那个最多的key;单独进行join,
尽可能地将key分散到各个task上去进行join操作。
sample采样倾斜key单独进行join -----》 网上资料介绍
就是说,咱们单拉出来了一个或者少数几个可能会产生数据倾斜的key,
然后还可以进行更加优化的一个操作;
对于那个key,从另外一个要join的表中,也过滤出来一份数据,比如可能就只有一条数据。
userid2infoRDD,一个userid key,就对应一条数据。
然后呢,采取对那个只有一条数据的RDD,进行flatMap操作,打上100个随机数,作为前缀,
返回100条数据。
单独拉出来的可能产生数据倾斜的RDD,给每一条数据,都打上一个100以内的随机数,作为前缀。
再去进行join,是不是性能就更好了。肯定可以将数据进行打散,去进行join。join完以后,
可以执行map操作,去将之前打上的随机数,给去掉,然后再和另外一个普通RDD join以后的结果,
进行union操作。
什么时候不适用呢???
如果一个RDD中,导致数据倾斜的key,特别多;那么此时,最好还是不要这样了;
还是使用我们最后一个方案,终极的join数据倾斜的解决方案。
611行
sample采样倾斜key单独进行join
就是说,咱们单拉出来了一个或者少数几个可能会产生数据倾斜的key,
然后还可以进行更加优化的一个操作;
对于那个key,从另外一个要join的表中,也过滤出来一份数据,比如可能就只有一条数据。
userid2infoRDD,一个userid key,就对应一条数据。
然后呢,采取对那个只有一条数据的RDD,进行flatMap操作,打上100个随机数,作为前缀,
返回100条数据。
单独拉出来的可能产生数据倾斜的RDD,给每一条数据,都打上一个100以内的随机数,作为前缀。
再去进行join,是不是性能就更好了。肯定可以将数据进行打散,去进行join。join完以后,
可以执行map操作,去将之前打上的随机数,给去掉,然后再和另外一个普通RDD join以后的结果,
进行union操作。
D,数据倾斜解决方案 使用随机数以及扩容表进行join
当采用随机数和扩容表进行join解决数据倾斜的时候,就代表着,你的之前的数据倾斜的解决方案,
都没法使用。
这个方案是没办法彻底解决数据倾斜的,更多的,是一种对数据倾斜的缓解。
原理,其实在上一讲,已经带出来了。
步骤:
1、选择一个RDD,要用flatMap,进行扩容,将每条数据,映射为多条数据,每个映射出来的数据,
都带了一个n以内的随机数,通常来说,会选择10。
2、将另外一个RDD,做普通的map映射操作,每条数据,都打上一个10以内的随机数。
3、最后,将两个处理后的RDD,进行join操作。
局限性:
1、因为你的两个RDD都很大,所以你没有办法去将某一个RDD扩的特别大,一般咱们就是10倍。
2、如果就是10倍的话,那么数据倾斜问题,的确是只能说是缓解和减轻,不能说彻底解决。
sample采样倾斜key并单独进行join
将key,从另外一个RDD中过滤出的数据,可能只有一条,或者几条,此时,咱们可以任意进行扩容,
扩成1000倍。
将从第一个RDD中拆分出来的那个倾斜key RDD,打上1000以内的一个随机数。
这种情况下,还可以配合上,提升shuffle reduce并行度,join(rdd, 1000)。通常情况下,
效果还是非常不错的。
打散成100份,甚至1000份,2000份,去进行join,那么就肯定没有数据倾斜的问题了吧。
第一个模块的简单总结:
1、完整的大数据项目开发流程:数据分析、需求分析、技术方案设计、数据表设计、代码编写、
功能测试、性能调优、(上线)troubleshooting、(上线)解决数据倾斜问题。
2、交互式大数据分析系统的架构:J2EE+Spark;
3、基础组件:企业级大数据项目,spark工程,架构
4、复杂的用户分析的业务:聚合统计、按时间比例随机抽取、复杂排序、取topn、用户行为分析
5、spark的各种算子:map、reduce、join、group
6、spark的高级技术点:自定义Accumulator、随机抽取算法、二次排序、分组取TopN
7、性能调优:普通调优、jvm调优、shuffle调优、算子调优
8、troubleshooting:多个实际生产环境中的,线上复杂报错问题的,剖析和解决方案
9、(高端)全套的数据倾斜解决方案:原理+现象+定位、7种解决方案