hive JdbcStorageHandler 导入过程中的数据倾斜问题
问题描述
为了提高hive导入的效率,添加了以下表属性来进行分片
- hive.sql.numPartitions: 为数据源生成多少个分片,如果不需要拆分则设置为 1
- hive.sql.partitionColumn: 需要对哪个列进行拆分。
TBLPROPERTIES (
..............
"hive.sql.partitionColumn" = "id",
"hive.sql.numPartitions" = "15",
.............
.............
);
但在对其中一个表进行优化时遇到了一个问题,不管怎么调分区数目‘hive.sql.numPartitions’的大小,最后一个任务执行时间远比其他任务的时间长,其他任务执行时间都是几十秒,最后一个任务的时间超过30分钟,分析可能存在主键分布有热点,发生了数据倾斜。
可以看到大部分的task都是在一分钟内执行完了,而task14还在执行,很明显发生了数据倾斜
进入日志进行分析
查看用时最长的任务task14的任务发现,他是卡在了records read -10000000,而其他task中的数据量只有10000级别,发生了很严重的数据倾斜。
解决方法
-
进入日志分析发现数据的主键大量聚集在最后一个task任务,找到它的分片区间[179813762,205501625) -
添加两个表属性,让 “hive.sql.lowerBound” = “热键区间的下界”, “hive.sql.upperBound” = “热键区间的上界”,
TBLPROPERTIES (
. . . . . .
"hive.sql.partitionColumn" = "id",
"hive.sql.numPartitions" = "15",
"hive.sql.lowerBound" = "179813762",
"hive.sql.upperBound" = "205501625",
. . . . . .
);
优化结果
执行时间变为了7min,基本解决了数据倾斜问题。,但是还是存在大量task的只用了几十秒就结束了,原因是"hive.sql.lowerBound" 和的范围hive.sql.upperBound"还是太大,可以根据日志分析进一步进行优化。
优化前用时
优化后用时
优化思路
有关参数介绍
“hive.sql.lowerBound"和"hive.sql.upperBound” 这两个参数用于拆分 partitionColumn 计算间隔的下限/上限。如果未定义,Hive 将对数据源执行 MIN/MAX 查询以获得下限/上限。而之所以发生数据倾斜,就是执行 MIN/MAX 查询以获得下限和上限的范围很大,而实际大部分的数据都集中在相对很小的区间中。而hive进行分区的时候,他会将upperBound和lowerBound的差值平均分成numPartitions个部分,每部分大小average=(upperBound-lowerBound)/numPartitions,划分后的分片分别是(,lowerBound+average)… …[upperBound-average,)。
官方的例子
TBLPROPERTIES (
. . . . . .
"hive.sql.table" = "DEMO",
"hive.sql.partitionColumn" = "num",
"hive.sql.numPartitions" = "3",
"hive.sql.lowerBound" = "1",
"hive.sql.upperBound" = "10",
. . . . . .
);
这种表将会拆分成 3 个分片,(,4) , [4,7) , [7,) 也就是 num<4 or num is null, 4< =num<7, num>=7
思路
优化关键就是尽可能缩小锁定发生主键热点的区域,让upperBound和lowerBound分别的作为该区域的上界和下界,使得发生主键热点的区域能够尽可能被分片。来优化hive导入的时间。
存在问题
还是会有很多task是几秒钟就执行完了,还是有资源浪费,这需要进一步调节upperBound和lowerBound的界限。但每天的数据都会更新,产生热键的分片也会变化,但好在不会有太大浮动,只能综合这些因素来调节upperBound和lowerBound的范围。
Bound和lowerBound的界限。但每天的数据都会更新,产生热键的分片也会变化,但好在不会有太大浮动,只能综合这些因素来调节upperBound和lowerBound的范围。
|