A,数据倾斜解决方案  使用随机key实现双重聚合


使用随机key实现双重聚合


1、原理
这个方案的核心实现思路就是进行两阶段聚合。第一次是局部聚合,先给每个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)。


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操作,flatMap?!


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比较小的情况下。


不适合的情况???


两个RDD都比较大,那么这个时候,你去将其中一个RDD做成broadcast,就很笨拙了。
很可能导致内存不足。最终导致内存溢出,程序挂掉。




564行
reduce join转换为map join


对于join这种操作,不光是考虑数据倾斜的问题;即使是没有数据倾斜问题,也完全可以优先考虑,
用我们讲的这种高级的reduce join转map join的技术,不要用普通的join,去通过shuffle,
进行数据的join;完全可以通过简单的map,使用map join的方式,牺牲一点内存资源;
在可行的情况下,优先这么使用。
不走shuffle,直接走map.




C,数据倾斜解决方案  sample采样倾斜key单独进行join


方案适用场景:两个RDD/Hive表进行join的时候,如果数据量都比较大,无法采用“解决方案五”,那么此时可以看一下两个RDD/Hive表中的key分布情况。如果出现数据倾斜,是因为其中某一个RDD/Hive表中的少数几个key的数据量过大,而另一个RDD/Hive表中的所有key都分布比较均匀,那么采用这个解决方案是比较合适的。


方案实现思路: (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即可。


(6)最后将两次join的结果使用union算子合并起来即可,就是最终的join结果。






什么时候不适用呢???


如果一个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操作时,RDD中有大量的key导致数据倾斜,那么进行分拆key也没什么意义,此时就只能使用最后一种方案来解决问题了。


方案实现思路:


该方案的实现思路基本和“解决方案六”类似,首先查看RDD/Hive表中的数据分布情况,找到那个造成数据倾斜的RDD/Hive表,比如有多个key都对应了超过1万条数据。
然后将该RDD的每条数据都打上一个n以内的随机前缀。
同时对另外一个正常的RDD进行扩容,将每条数据都扩容成n条数据,扩容出来的每条数据都依次打上一个0~n的前缀。
最后将两个处理后的RDD进行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种解决方案