数据倾斜本质:Shuffle 阶段,某一个 / 某几个 Reduce 接收的数据量远大于其他 Reduce,任务长时间卡在这几个 Reduce,出现长尾任务,严重时 OOM。
一、现象识别(怎么判断发生倾斜)
现象 1:YARN 页面观察
- 大部分 Reduce 任务快速跑完,少数几个 Reduce 进度卡在 99%、100% 很久不动,耗时远高于其余 task。
- 看 Counters →
Reduce input records计数器:- 绝大多数 reduce 输入记录数几万,个别 reduce 几百万、上千万条,数量差距几十上百倍。
✔ Counter 只能确认倾斜发生,看不到具体热点 key。
现象 2:日志异常
- 慢 Reduce 的 Container 日志:频繁 Full GC、OOM、内存溢出报错。
- Task 日志大量重复相同 key。
现象 3:Hive SQL 表现
- Map 阶段很快结束,MR Job 卡在 Reduce 阶段,任务跑很久不结束。
二、完整排查步骤
-
确认是否发生数据倾斜 :YARN UI 打开对应 Job → Counters 标签,查看
Reduce input records。如果个别 reduce 输入记录数远超其他,确认倾斜。 -
定位出有问题的 Reduce Task:进入 Job 的 Attempts/Container 列表,找到执行时间极长、进度停滞的 Reduce 任务,复制该 Container ID。
-
下载该 Reduce Task 日志,定位热点 Key :打开该 container 日志,搜索 key 相关打印,找到数量爆炸的热点 key 具体值。
注意:MR 原生计数器不保存 key,日志才能拿到真实 key。
-
分析倾斜产生的根因 :拿到热点 key 后分析业务:
- 大量 null、空字符串 key;
- 某个业务 key 数据量异常大;
- join 的一侧存在大量重复 key;
- 分区函数不合理。
-
区分倾斜类型 :
- ✅ Group By / 聚合倾斜:group by 的某个 key 值数据量巨大
- ✅ Join 倾斜:join 的其中一张表有大量重复 join key
- ✅ Count Distinct 倾斜:去重,相同 key 过多
三、常见倾斜分类 + Hive 解决方案
类型 1:group by 数据倾斜(聚合倾斜)
场景:group by 某个字段,某个 key 行数特别多。现象:reduce 输入记录数严重不均。
优化方案
-
开启 map 端预聚合
set hive.map.aggr=true; --map端局部聚合
set hive.groupby.mapaggr.checkinterval=100000; -
开启倾斜自动处理
set hive.groupby.skewindata=true;
原理:拆两轮 MR。第一轮随机打散做局部聚合;第二轮再汇总。代价:多一轮 MR,消耗资源。
类型 2:Join 数据倾斜
场景:大表 join 大表,join key 存在热点;或者大表 join 小表但 key 热点。
方案 A:小表侧 mapjoin(小表全部加载到 map 内存,无 shuffle,不走 reduce join)
set hive.auto.convert.join=true;
set hive.mapjoin.smalltable.filesize=25000000;
适用:一张表很小,另一张大表。
方案 B:热点 key 打散(大表 join 大表,存在热点 key)
思路:
- 对大表热点 key,拼接随机前缀打散,分到不同 reduce;
- 另外一张表,把热点 key 复制 N 份,带上对应随机前缀;再做 join。
适合:join 的热点 key 只是少数,其他 key 正常。
方案 C:分离热点 key 单独处理
把热点 key 过滤出来单独做 join;非热点 key 正常 join;最后把两部分结果 union all 合并。
类型 3:null / 空值 key 导致倾斜
场景:大量记录 join/group by 的 key 为 null、空字符串,全部 hash 到同一个 reduce。优化:
-
过滤掉 null(业务允许情况下);
-
null 值给随机前缀打散,不让全部落到同一个 reduce。
-- 示例,null打上随机数
case when key is null then concat('rand_',rand()) else key end as join_key
类型 4:count distinct 去重倾斜
count (distinct id),同一个 id 数量巨大,shuffle 全部落到同一个 reduce。优化:先 group by 去重,再 count。
--倾斜写法
select count(distinct id) from table;
--优化改写
select count(*) from (select id from table group by id) t;
四、参数
--开启mapjoin
set hive.auto.convert.join=true;
--groupby倾斜优化
set hive.groupby.skewindata=true;
--map端聚合
set hive.map.aggr=true;
--倾斜join自动优化(hive新版本)
set hive.optimize.skewjoin=true;
set hive.skewjoin.key=100000;
五、精简版
排查数据倾斜,首先看 YARN 任务 Counter 中 Reduce-input-records,观察每个 reduce 输入数据量,如果少数 reduce 数据量远大于其他,确认发生数据倾斜。然后找到耗时很长的那个 reduce 对应的 Container,下载 task 日志,从中定位热点 key。
倾斜主要分 groupby 聚合倾斜、join 倾斜、null 值倾斜、count distinct 倾斜。优化手段有 map 端预聚合、skewindata 开启两轮 MR、mapjoin、热点 key 打散、分离热点单独处理、改写 count distinct。
六、容易踩考点
- Counter 只能发现倾斜,不能直接看到热点 key,热点 key 要去 container 日志找。
- 数据倾斜发生在Shuffle 阶段。
- hive.groupby.skewindata=true 会把 group by 拆两轮 MR,会增加任务耗时,不要无脑开启。
- mapjoin 没有 shuffle 阶段,完全规避 join 倾斜,但受内存限制,只适合小表。