数据倾斜是大数据处理中常见的问题之一
一、数据倾斜的表现
任务进度长时间维持在99%(100%),查看任务监控页面(通过HPM、HSJO、HSJD、HSJR等监控工具),发现只要少量(1个或几个)reduce子任务未完成。其处理的数据量和其他reduce差异过大!
二、Hive数据倾斜监控工具
- Hadoop Job Progress Monitor(HPM):HPM是一个基于Web的Hadoop作业监控工具,可以监控Hive作业的进度和状态,支持查看Hive作业的Map和Reduce阶段的进度和数据分布情况,可以帮助用户发现数据倾斜的问题。
- Hive Skew Join Optimize(HSJO):HSJO是一个基于Hive的数据倾斜自动优化工具,可以自动检测并优化Hive中的数据倾斜问题。它通过在Hive查询语句中自动加入一些优化语句,例如在Join操作中加入Map端Aggregation或使用Bucket等技术,从而解决数据倾斜问题。
- Hive Skew Join Detector(HSJD):HSJD是一个基于Hive的数据倾斜检测工具,可以帮助用户发现Hive查询中可能存在的数据倾斜问题。它通过检测Hive查询语句中的Join操作和Group By操作,分析数据分布情况,从而判断是否存在数据倾斜问题。
- Hive Skew Join Resolver(HSJR):HSJR是一个基于Hive的数据倾斜解决工具,可以帮助用户解决Hive查询中的数据倾斜问题。它通过在Hive查询语句中自动加入一些优化语句,例如在Join操作中使用Map端Aggregation或使用Bucket等技术,从而解决数据倾斜问题。
这些工具都可以帮助我们监控和解决Hive数据倾斜问题。
三、当工具无法解决数据倾斜,可以处理思路:
可以从业务层和Join两个方向考虑:
1. 业务层面优化
1.不要使用select * from your_table这样的方式,用到哪些列就指定哪些列,where条件中也添加过滤条件,以去掉无关的数据行。
2.输入文件不要是大量的小文件。Hive的默认Input Split是128MB(可配置),小文件可先合并成大文件。
2. join无关的优化
1)group by 引起的数据倾斜优化
group by引起的倾斜主要是输入数据行按照group by列分布不均匀引起的。
set hive.map.aggr = true
set hive.groupby.skewindata = true
2) count distinct优化
select count(*) from (select user from tem_table group by user) a;
--利用group by去重,再统计group by的行数目(不过这种方式需要注意数据倾斜的问题)。
3.join相关的优化
1)mapjoin可以解决的join优化(即大表join小表):
通常情况下,JOIN操作在Reduce阶段执行表连接,整个JOIN过程包含Map、Shuffle、Reduce三个阶段。MAPJOIN在Map阶段执行表连接,而非等到Reduce阶段才执行表连接。
(在大表和一个或多个小表JOIN的场景下,MAPJOIN会将您指定的小表全部加载到执行JOIN操作的程序的内存中,因此指定的表仅能为小表。)
打开参数:Hive对于mapjoin是默认开启的,设置参数为:
set hive.auto.convert.join=true;
2)mapjoin无法解决的join优化(即大表join大表)
join 超时是因为某些 key 对应的数据太多,而相同 key 对应的数据都会发送到相同。
- a.空 key 过滤 。 (where a is null)
如果 key 对应的字段为空,且是异常数据,应该在join前直接过滤掉。
select n.*
from nullidtable n
left join bigtable b
on n.id = b.id
and b.region is null;
- b.空 key 转换
有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在 join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,
使得数据随机均匀地分不到不同的 reducer 上(这里的处理方式其实跟前面的group by的优化类似,这做空 key 转换的优化演示)。
-- 空 key 转换前
select n.* from nullidtable n left join bigtable b on n.id = b.id;
-- 空 key 转换后
select n.* from nullidtable n full join bigtable o on nvl(n.id,rand()) = o.id;