spark 数据倾斜优化总结

一、数据倾斜产生原因

数据倾斜就是部分task承担了过多的计算任务,导致整个stage都被卡。

可能产生数据倾斜的场景如下

操作 场景
join 其中一个表比较小,但key值少
join 大表与大表,但key值中存在过多的特殊值,如0或null
join on条件包含key值过滤逻辑,导致部分数据被保留,部分被过滤,最终节点分布不均
join 多对多关系表join导致数据膨胀
group by 某个组合数量特别多
count distinct 需要集中最后一个reduce节点处理,特殊值多就会慢
使用脚本或udf 会存在强制数据分布在少量节点的可能
distriute by 存在值不均匀的可能
读取 上游文件数过少,单个文件过大

二、数据倾斜优化

2.1 调参优化

参数 作用 备注
hive.map.aggr=true map端部分聚合 仅适用于hive引擎,不适用于spark。spark本身就支持map端的局部聚合
hive.groupby.skewindata=true 参数设置为true时,生成的查询计划会有2个MR job。第一个MR中,map的输出结果会随机分配到reduce中,每个reduce做部分聚合操作,并输出结果,这样相同的key会被分发到不同的reduce中,起到了负载均衡的目的,第二个MR再根据第一个MR预处理的结果,完成聚合操作 仅适用于hive引擎,spark不支持此参数

2.2 代码优化

2.2.1 join类操作

  1. 如果是join操作,那么采用join key分布最均匀的表作为驱动表
  2. where类的操作在join前进行
2.2.1.1 小表join大表

使用 /*+mapjoin(a)*/ 让小的维度表先进内存,在map端完成reduce

使用此操作需要对小的维度表配置DQC数据量监控,以避免进入内存的维表数据过大

2.2.1.2 中表join大表

在维表大小中等,完全进入内存可能报错;但日志与维表关联部分出现某种行为的维值较少时,可以采用两次 mapjoin 的方式优化倾斜问题。例,有交易日志log,和维表dim,它们2次join示例如下

sql 复制代码
select /*+mapjoin(b)*/
    a.*, 
    b.*
from log a
left join (
    select /*+mapjoin(d)*/
           c.*
      from dim AS c
            join (
                select dim_id
                 from log
                group by dim_id
            ) AS d 
            on c.dim_id = d.dim_id
    ) AS b 
 on a.dim_id = b.dim_id
2.2.1.3 大表join大表

大表join大表一般由于key值存在 null 等特殊值,导致数据过于集中倾斜。这种情况可以使用hash函数将key打散。这里不要用rand,因为fetch failed后,整个job会被kill

2.2.1.4 join条件包含key值过滤逻辑

尽量在join前使用where过滤

2.2.1.5 多对多关系表join
  1. 去掉热点大key
  2. 增加关联条件
  3. 减少数据范围,笛卡尔积结果尽量控制1亿

2.2.2 group by操作

将倾斜数据拿出来单独处理,后面再union 回去

2.2.3 count distinct操作

2.2.3.1 单个 count distinct

可以将它转换为count+group by。如果单个值数据量比较集中,可以过滤该值,结果+1.

下面的示例是从t表中取user_id的uv。其中,user_id有大量为0的异常值

优化前

sql 复制代码
select count(distinct user_id) as uv from t

优化后

sql 复制代码
select count(user_id) +1 as uv
   from (
   	select user_id
   	  from t
   	 where user_id != 0
   	 group by user_id
)
2.2.3.1 多个 count distinct

如果多个count distinct,去重的键是一样的,如对用户计算uv和去作弊uv,那么仍可按user_id去重后,根据是否作弊按0,1进行SUM。

如果去重的键是不一样的,那么多个count distinct 可以优化为多个group by再union all的方式。但这会扫描多次表,具体优化效果需根据具体情况测试确定。

2.2.4 使用脚本或udf

这个需要根据具体业务场景优化。如果不方便优化,可以降低 spark.sql.shuffle.partitions的值。

2.2.5 distriute by

distriute by 需要保证键比较均匀。同时,不能使用rand函数,否则shuffle fetch failed后,整个job会被kill

2.2.6 读取操作

读取一般不会倾斜。出现倾斜一般是上游文件数过少,下游处理的executor多。spark默认一个executor对应一个文件,这样会有大量executor空跑。这种情况可以使用 distriute by、repartition 等对文件重新分区。

相关推荐
永洪科技4 小时前
永洪科技荣获商业智能品牌影响力奖,全力打造”AI+决策”引擎
大数据·人工智能·科技·数据分析·数据可视化·bi
weixin_307779135 小时前
Hive集群之间迁移的Linux Shell脚本
大数据·linux·hive·bash·迁移学习
ZHOU_WUYI5 小时前
一个简单的分布式追踪系统
分布式
上海锝秉工控8 小时前
防爆拉线位移传感器:工业安全的“隐形守护者”
大数据·人工智能·安全
cv高级工程师YKY8 小时前
SRE - - PV、UV、VV、IP详解及区别
大数据·服务器·uv
bxlj_jcj9 小时前
深入Flink核心概念:解锁大数据流处理的奥秘
大数据·flink
云资源服务商9 小时前
阿里云Flink:开启大数据实时处理新时代
大数据·阿里云·云计算
码不停蹄的玄黓9 小时前
MySQL分布式ID冲突详解:场景、原因与解决方案
数据库·分布式·mysql·id冲突
Aurora_NeAr10 小时前
Spark SQL架构及高级用法
大数据·后端·spark
王小王-12310 小时前
基于Hadoop的公共自行车数据分布式存储和计算平台的设计与实现
大数据·hive·hadoop·分布式·hadoop公共自行车·共享单车大数据分析·hadoop共享单车