4. 定位 SQL 代码
1. 确定任务卡住的 stage
- 通过 jobname 确定 stage:
一般 Hive 默认的 jobname 名称会带上 stage 阶段,如下通过 jobname 看到任务卡住的为 Stage-4:
- 如果 jobname 是自定义的,那可能没法通过 jobname 判断 stage。需要借助于任务日志:
找到执行特别慢的那个 task,然后 Ctrl+F 搜索 “CommonJoinOperator: JOIN struct” 。Hive 在 join 的时候,会把 join 的 key 打印到日志中。如下:
上图中的关键信息是:struct<_col0:string, _col1:string, _col3:string>
这时候,需要参考该 SQL 的执行计划。通过参考执行计划,可以断定该阶段为 Stage-4 阶段:
2. 确定 SQL 执行代码
确定了执行阶段,即 stage。通过执行计划,则可以判断出是执行哪段代码时出现了倾斜。还是从此图,这个 stage 中进行连接操作的表别名是 d:
就可以推测出是在执行下面红框中代码时出现了数据倾斜,因为这行的表的别名是 d:
5. 解决倾斜
我们知道了哪段代码引起的数据倾斜,就针对这段代码查看倾斜原因,看下这段代码的表中数据是否有异常。
倾斜原因:
本文的示例数据中 user_info 和 user_order 通过身份证号关联,检查发现 user_info 表中身份证号为空的有 7000 多万,原因就是这 7000 多万数据都分配到一个 reduce 去执行,导致数据倾斜。
解决方法:
- 可以先把身份证号为空的去除之后再关联,最后按照 userkey 连接,因为 userkey 全部都是有值的:
with t1 as( select u.userkey, o.* from user_info u left join user_order o on u.idno = o.idno where u.idno is not null --是可以把where条件写在后面的,hive会进行谓词下推,先执行where条件在执行 left join ) select a.userkey, a.idno, a.phone, a.name, b.user_active_at, c.intend_commodity, c.intend_rank, d.order_num, d.order_amount from user_info a left join user_active b on a.userkey = b.userkey left join user_intend c on a.phone = c.phone left join t1 d on a.userkey = d.userkey;
- 也可以这样,给身份证为空的数据赋个随机值,但是要注意随机值不能和表中的身份证号有重复:
select a.userkey, a.idno, a.phone, a.name, b.user_active_at, c.intend_commodity, c.intend_rank, d.order_num, d.order_amount from user_info a left join user_active b on a.userkey = b.userkey left join user_intend c on a.phone = c.phone left join user_order d on nvl(a.idno,concat(rand(),'idnumber')) = d.idno;
其他的解决数据倾斜的方法:
1. 过滤掉脏数据
如果大 key 是无意义的脏数据,直接过滤掉。本场景中大 key 有实际意义,不能直接过滤掉。
2. 数据预处理
数据做一下预处理(如上面例子,对 null 值赋一个随机值),尽量保证 join 的时候,同一个 key 对应的记录不要有太多。
3. 增加 reduce 个数
如果数据中出现了多个大 key,增加 reduce 个数,可以让这些大 key 落到同一个 reduce 的概率小很多。
配置 reduce 个数:
set mapred.reduce.tasks = 15;
4. 转换为 mapjoin
如果两个表 join 的时候,一个表为小表,可以用 mapjoin 做。
配置 mapjoin:
set hive.auto.convert.join = true; 是否开启自动mapjoin,默认是true set hive.mapjoin.smalltable.filesize=100000000; mapjoin的表size大小
5. 启用倾斜连接优化
hive 中可以设置 hive.optimize.skewjoin
将一个 join sql 分为两个 job。同时可以设置下 hive.skewjoin.key
,此参数表示 join 连接的 key 的行数超过指定的行数,就认为该键是偏斜连接键,就对 join 启用倾斜连接优化。默认 key 的行数是 100000。
配置倾斜连接优化:
set hive.optimize.skewjoin=true; 启用倾斜连接优化 set hive.skewjoin.key=200000; 超过20万行就认为该键是偏斜连接键
6. 调整内存设置
适用于那些由于内存超限任务被 kill 掉的场景。通过加大内存起码能让任务跑起来,不至于被杀掉。该参数不一定会明显降低任务执行时间。
配置内存:
set mapreduce.reduce.memory.mb=5120; 设置reduce内存大小 set mapreduce.reduce.java.opts=-Xmx5000m -XX:MaxPermSize=128m;
附:Hive 配置属性官方链接:
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties