写点什么

hive 数据倾斜解决办法

发布于: 2021 年 03 月 21 日
hive数据倾斜解决办法

从 map 的数量角度


  • 1)通常情况下,作业会通过 input 的目录产生一个或者多个 map 任务。


    主要的决定因素有:input的文件总个数,input的文件大小,集群设置的文件块大小(目前为128M,可在hive中通过set dfs.block.size;命令查看到,该参数不能自定义修改);
复制代码
  • 2)举例:


    a)  假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数。
复制代码


    b) 假设input目录下有3个文件a,b,c大小分别为10m,20m,150m,那么hadoop会分隔成4个块(10m,20m,128m,22m),从而产生4个map数。即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。
复制代码
  • 3)是不是 map 数越多越好?


    答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的。
复制代码
  • 4)是不是保证每个 map 处理接近 128m 的文件块,就高枕无忧了?


    答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。
复制代码


针对上面的问题3和4,我们需要采取两种方式来解决:即减少map数和增加map数;
复制代码

2 小文件的合并


在 map 执行前合并小文件,减少 map 数:


1) 参数设置(下面的 API 属于 hadoop 低版本的 API)


set mapred.max.split.size=112345600;
set mapred.min.split.size.per.node=112345600;
set mapred.min.split.size.per.rack=112345600;
set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 这个参数表示执行前进行小文件合并,前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),进行合并
复制代码

3 如何适当的增加 map 数


当 input 的文件都很大,任务逻辑复杂,map 执行非常慢的时候,可以考虑增加 Map 数,来使得每个 map 处理的数据量减少,从而提高任务的执行效率。


假设有这样一个任务:

Select data_desc,count(1),count(distinct id),sum(case when …),sum(case when …),sum(…)from a group by data_desc
复制代码


如果表 a 只有一个文件,大小为 120M,但包含几千万的记录,如果用 1 个 map 去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,这样就可以用多个 map 任务去完成。


set mapreduce.job.reduces =10;
复制代码


create table a_1 as select * from a distribute by rand(123);
复制代码

这样会将 a 表的记录,随机的分散到包含 10 个文件的 a_1 表中,再用 a_1 代替上面 sql 中的 a 表,则会用 10 个 map 任务去完成。


每个 map 任务处理大于 12M(几百万记录)的数据,效率肯定会好很多。


看上去,貌似这两种有些矛盾,一个是要合并小文件,一个是要把大文件拆成小文件,这点正是重点需要关注的地方,根据实际情况,控制 map 数量需要遵循两个原则:使大数据量利用合适的 map 数;使单个 map 任务处理合适的数据量;


发布于: 2021 年 03 月 21 日阅读数: 10
用户头像

还未添加个人签名 2020.11.10 加入

专注于大数据技术

评论

发布
暂无评论
hive数据倾斜解决办法