定义
在分布式系统中,结果集合往往按照分片(slices)存储和处理,数据倾斜(Data Skew)主要是指数据分片的不均匀分布。不同的组件会产生不同的倾斜。
组件 | 倾斜现象 |
---|---|
Kafka | Kafka 数据倾斜:大量数据被发送到了Kafka 中一个partition。 |
Spark | Spark 数据倾斜:大量数据被发送到了Spark 的一个task。 |
Hive | Hive 数据倾斜:大量数据被发送到了Hive 的一个reduce。分为Mapper Skew和Reducer Skew |
Redis | 大量数据都存到了Redis 集群中的一个节点中 |
如何判断是否发生了数据倾斜
- 方法1:通过时间判断:如果某个 reduce 的时间比其他 reduce 时间长的多,
分析执行日志,作业在reduce阶段停留在99%,很长时间完成不了,很可能不分任务执行时间较短,部分任务执行时间较长。下图来自于Dr.drelephant,GroupA 110个任务平均每个5MB,而Group 25个任务平均128MB。时间倾斜,GroupA 110个任务耗时6min,GroupB共25个任务,每个128MB,其余运行时间是26分钟。
- 方法2:分析执行日志,作业在reduce阶段停留在99%,很长时间完成不了,很可能发生了数据倾斜。
如何解决?
Group by 聚合倾斜
原因
分组的维度过少,每个维度的值过多,导致处理某值的reduce耗时很久;
对一些类型统计的时候某种类型的数据量特别多,其他的数据类型特别少。当按照类型进行group by的时候,会将相同的group by字段的reduce任务需要的数据拉取到同一个节点进行聚合,而当其中每一组的数据量过大时,会出现其他组的计算已经完成而这个reduce还没有计算完成,其他的节点一直等待这个节点的任务执行完成,所以会一直看到map 100% reduce99%的情况;
解决办法
-- 是否开启map的聚合(默认为true)
set hive.map.aggr=true;
set hive.map.aggr.hash.force.flush.memory.threshold=0.9
set hive.map.aggr.hash.min.reduction=0.5
set hive.map.aggr.hash.percentmemory=0.5
-- 在 Map 端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval=100000;
-- 发生数据倾斜时,进行负载均衡
set hive.groupby.skewindata=true;
原理
map端聚合原理:使用内存中的hash table来保存聚合结果。
hive.groupby.skewindata=true,当选项设定为true,生成的查询计划会有两个MR Job。当第一个MR Job中,Map的输出结果结合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果。这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的。第二个MR Job再根据预处理的数据结果按照Group By Key分布到reduce中,这个过程可以保证相同的key被分到同一个reduce中,最后完成最终的聚合操作。
Join 倾斜
原因
假设事实表fact有1亿条记录,其中字段code_id有1万个枚举值(维表dimension),其中code_id=1点有9900万条,剩余的100万条记录都code_id是其他枚举值。此处事实表fact在code_id=1是有数据倾斜。
解决办法
分离查询
select
*
from
FACT f
left join DIMENSION d
on f.CODE_ID = d.CODE_ID
where
f.CODE_ID <> 1
union
select
*
from
FACT f
left join DIMENSION d
on f.CODE_ID = d.CODE_ID
where
f.CODE_ID = 1
and d.CODE_ID = 1
参数调优
set hive.optimize.skewjoin=true;
set hive.skewjoin.key=500000;
set hive.skewjoin.mapjoin.map.tasks=10000;
_hive.optimize.skewjoin_
,检测到存储join倾斜时,存储到HDFS临时目录,通过map join方式避免数据倾斜。
Dr.Elephant如何自动检测数据倾斜
Dr.Elephant是一个Hadoop和Spark性能监控和调优工具。代码见:https://github.com/linkedin/dr-elephant
下面以Mapper数据倾斜为例,介绍数据倾斜的计算方法。
判断依据
数据进入到Mapper作业中后,有可能会发生数据的倾斜,这种数据倾斜主要是考虑到HDFS文件大小差别太大导致的。
原理
Mapper数据倾斜启发式算法(mapperdata skew heuristic)会将所有的Mapper分成两部分,其中一部分的所有作业(task)的平均数据量会大于另一部分的平均数据量,之后根据这两个组的平均数据量的差值的绝对值/这两组数据中平均数据量的最小值来判断数据倾斜程度。时间方面的倾斜程度算法一样。
此图中的A和B两组的平均数据量和平均运行时间都差不多,没有发生数据倾斜。
计算步骤
(1)递归的计算作业输入数据量的平均值,然后根据作业的输入量平均值将所有的作业分成两组Group_A 和Group_B。
(2)计算各组的平均值,并求出数据量小的组的平均值(minAvg)和两组平均值之差的绝对值(diffAvgAbs)
(3)求出误差( diffAvgAbs/ minAvg ),根据误差和给定的误差级别(比如:{2, 4, 8, 16})计算严重程度severity
(4)计算出数据量小的那组的的task数量,并根据配置的task数量级别(比如:{10, 50, 100, 200})计算出task数量的严重程度taskSeverity
(5)取数据量大的那组的平均数据量,并根据配置的文件大小级别(比如:{1d / 8, 1d / 4, 1d / 2, 1d}其中的每个值需要乘以block的大小)计算出task数据量的严重程度fileSeverity
(6)求出上面计算出来的严重程度的最小值作为map 数据倾斜程度的结果。