其余更多java基础文章:
java基础学习(目录)java
学习资料:数据倾斜是多么痛?spark做业/面试/调优必备秘籍面试
数据倾斜是一种很常见的问题(依据二八定律),简单来讲,比方WordCount中某个Key对应的数据量很是大的话,就会产生数据倾斜,致使两个后果:算法
Shuffle时,需将各节点的相同key的数据拉取到某节点上的一个task来处理,若某个key对应的数据量很大就会发生数据倾斜。比方说大部分key对应10条数据,某key对应10万条,大部分task只会被分配10条数据,很快作完,个别task分配10万条数据,不只运行时间长,且整个stage的做业时间由最慢的task决定。sql
数据倾斜只会发生在Shuffle过程,如下算法可能触发Shuffle操做: distinct、groupByKey、reduceByKey、aggregateByKey、join、cogroup、repartition等。函数
步骤一: 看数据倾斜发生在哪一个stage(也就是看以上算子出如今哪一个阶段)。yarn-client模式下查看本地log或Spark Web UI中当前运行的是哪一个stage;yarn-cluster模式下,经过Spark Web UI查看运行到了哪一个Stage。 主要看最慢的Stage各task分配的数据量,来肯定是不是数据倾斜。post
步骤二:根据Stage划分,推算倾斜发生的代码(必然有Shuffle类算子)。简单实用方法:只要看到shuffle类算子或Spark SQL的SQL语句会有Shuffle类的算子的句子,就能够该地方划分为先后两个Stage。(以前用Python的PySpark接口,Spark Web UI会查看task在源码中的行数,Java或者Scala虽没用过,但我想应该有)学习
场景:若Hive表中数据不均匀,且业务中会频繁用Spark对Hive表分析;
思路:用Hive对数据预处理(对key聚合等操做),本来是Spark对Hive的原表操做,如今就是对Hive预处理后的表操做;
原理:从根源解决了数据倾斜,规避了了Spark进行Shuffle类算子操做。但Hive ETL中进行聚合等操做会发生数据倾斜,只是把慢转移给了Hive ETL;
优势:方便,效果好,规避了Spark数据倾斜;
缺点:治标不治本,Hive ETL会数据倾斜。spa
场景:发生倾斜的key不多且不重要;
思路:对发生倾斜的key过滤掉。比方在Spark SQL中用where子句或filter过滤,若每次做业执行,须要动态断定可以使用sample算子对RDD采样后取数据量最多的key过滤;
原理:对倾斜的key过滤后,这些key便不会参与后面的计算,从本质上消除数据倾斜;
优势:简单,效果明显;
缺点:适用场景少,实际中致使倾斜的key不少。接口
场景:任何场景均可以,优先选择的最简单方案;
思路:对RDD操做的Shuffle算子传入一个参数,也就是设置Shuffle算子执行时的Shuffle read task数量。对于Spark SQL的Shuffle类语句(如group by,join)即spark.sql.shuffle.partitions,表明shuffle read task的并行度,默认值是200可修改;
原理:增大shuffle read task参数值,让每一个task处理比原来更少的数据;
优势:简单,有效;
缺点:缓解的效果颇有限。内存
场景:对RDD进行reduceByKey等聚合类shuffle算子,SparkSQL的groupBy作分组聚合这两种状况
思路:首先经过map给每一个key打上n之内的随机数的前缀并进行局部聚合,即(hello, 1) (hello, 1) (hello, 1) (hello, 1)变为(1_hello, 1) (1_hello, 1) (2_hello, 1),并进行reduceByKey的局部聚合,而后再次map将key的前缀随机数去掉再次进行全局聚合;
原理:对本来相同的key进行随机数附加,变成不一样key,让本来一个task处理的数据分摊到多个task作局部聚合,规避单task数据过量。以后再去随机前缀进行全局聚合;
优势:效果很是好(对聚合类Shuffle操做的倾斜问题);
缺点:范围窄(仅适用于聚合类的Shuffle操做,join类的Shuffle还需其它方案)。
场景:对RDD或Spark SQL使用join类操做或语句,且join操做的RDD或表比较小(百兆或1,2G); 思路:使用broadcast和map类算子实现join的功能替代本来的join,完全规避shuffle。对较小RDD直接collect到内存,并建立broadcast变量;并对另一个RDD执行map类算子,在该算子的函数中,从broadcast变量(collect出的较小RDD)与当前RDD中的每条数据依次比对key,相同的key执行你须要方式的join; 原理:若RDD较小,可采用广播小的RDD,并对大的RDD进行map,来实现与join一样的效果。简而言之,用broadcast-map代替join,规避join带来的shuffle(无Shuffle无倾斜); 优势:效果很好(对join操做致使的倾斜),根治; 缺点:适用场景小(大表+小表),广播(driver和executor节点都会驻留小表数据)小表也耗内存。
场景:两个较大的(没法采用方案五)RDD/Hive表进行join时,且一个RDD/Hive表中少数key数据量过大,另外一个RDD/Hive表的key分布较均匀(RDD中二者之一有一个更倾斜);
思路:
优势:前提是join致使的倾斜(某几个key倾斜),避免占用过多内存(只需对少数倾斜key扩容n倍);
缺点:对过多倾斜key不适用。
场景:RDD中有大量key致使倾斜; 思路:与方案六相似。
原理:与方案六只有惟一不一样在于这里对不倾斜RDD中全部数据进行扩大n倍,而不是找出倾斜key进行扩容(这是方案六);
优势:对join类的数据倾斜均可处理,效果很是显著;
缺点:缓解,扩容须要大内存。
【我的认为,这里和方案六同样,也须要对扩容的key对应的value最后减去(n-1),除非只需大小关系,对值没有要求】
实际中,需综合着对业务全盘考虑,可先用方案一和二进行预处理,同时在须要Shuffle的操做提高Shuffle的并行度,最后针对数据分布选择后面方案中的一种或多种。实际中须要对数据和方案思路理解灵活应用。