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 等对文件重新分区。

相关推荐
liliangcsdn1 小时前
LLM MoE 形式化探索
大数据·人工智能
天远云服2 小时前
Go 语言高并发实战:批量清洗天远借贷行为验证API (JRZQ8203) 的时间序列数据
大数据·api
Hello.Reader2 小时前
Flink 系统内置函数(Built-in Functions)分类、典型用法与选型建议
大数据·flink·excel
AI营销实验室2 小时前
AI 工具何高质量的为销售线索打分?
大数据·人工智能
打码人的日常分享3 小时前
企业数据资产管控和数据治理解决方案
大数据·运维·网络·人工智能·云计算
数字冰雹3 小时前
从“东数西算”到智慧机房:数字孪生如何重塑数据中心的“智能大脑”?
大数据·人工智能·数据可视化
qq_348231853 小时前
市场快评 · 今日复盘要点20251224
大数据
Wang's Blog3 小时前
Kafka: 分布式配置管理的核心挑战
分布式·kafka
TG:@yunlaoda360 云老大4 小时前
如何在华为云国际站代理商控制台进行SFS Turbo的基础状态核查?
大数据·服务器·华为云·php
Yyyyy123jsjs4 小时前
XAUUSD API 周末无推送,会影响回测与实盘一致性吗?
大数据·区块链