项目场景:
将hbase数据卸出到hive分区表:
项目场景:按省份分区(36个分区),数据量50亿,数据大小4T左右
使用动态分区时首先不要忘记的一些配置:
是否开启动态分区 hive.exec.dynamic.partition
动态分区是否使用严格模式 hive.exec.dynamic.partition.mode
MR总共可创建最大分区数 hive.exec.max.dynamic.partition.partitions (默认1000)以及当前节点可创建的最大分区数 hive.exec.max.dynamic.partition.partitions.pernode (默认100)
问题描述:
直接sql执行:
insert overwrite table test1 partition (prov_branch_code) select * from test2;
mapreduce执行4个多小时,map个数5501,reduce个数1099(默认的最大值),reduce有几个节点运行时间长。
原因分析:
数据偏移,有部分省份数据量大,造成部分节点运行缓慢
解决方案:
为了防止一个reduce处理写入一个分区导致速度严重降低,加入如下参数
SET hive.optimize.sort.dynamic.partition=false;。
又出现了新的问题: table_tmp表里面一共有4T的数据,一共可以分成36个分区,SQL运行的时候创建了5501个Mapper,0个Reducers。程序运行到一般左右的时候出现了以下的异常:
[Fatal Error] total number of created files now is 100385, which exceeds 100000. Killing the job.
并最终导致了SQL的运行失败。这个错误的原因是因为Hive对创建文件的总数有限制(hive.exec.max.created.files),默认是100000个,而这个SQL在运行的时候每个Map都会创建76个文件,对应了每个分区,所以这个SQL总共会创建5501 * 36 = 198036个文件,运行中肯定会出现上述的异常。为了能够成功地运行上述的SQL,最简单的方法就是加大hive.exec.max.created.files参数的设置。但是这有个问题,这会导致在hadoop中产生大量的小文件,因为source表的数据就4T,那么平均每个文件的大小=4T / 198036= 10.589MB,可想而知,十九万多个这么小的小文件对Hadoop来说是多么不好。那么有没有好的办法呢?有!
我们可以将dt相同的数据放到同一个Reduce处理,这样最多也就产生36个文件,将dt相同的数据放到同一个Reduce可以使用DISTRIBUTE BY dt实现,所以修改之后的SQL如下:
hive> insert overwrite table test partition(dt)
> select * from table_tmp
> DISTRIBUTE BY dt;
修改完之后的SQL
运行良好,并没有出现上面的异常信息,但是这里也有个问题,因为这36个分区的数据分布很不均匀,有些Reduce的数据有30多G,而有些Reduce只有几K,直接导致了这个SQL运行的速度很慢!
能不能将4T的数据均匀的分配给Reduce呢?可以!我们可以使用DISTRIBUTE BY rand()将数据随机分配给Reduce,这样可以使得每个Reduce处理的数据大体一致。对于4T的数据总共会起1099(默认最大值)的Reduces,修改的SQL如下:
hive> insert overwrite table test partition(dt)
> select * from iteblog_tmp
> DISTRIBUTE BY rand();
最终sql运行时间优化到1小时10分钟。
后来查看hdfs上文件时发现又部分分区下存在小文件的情况。
通过如下命令调整reduce个数:
set mapred.reduce.tasks= 600;---Reduce个数
最终sql执行时长为50分钟。