因为Hive底层就是MR,所以问题实际是MR如何确定map数量和reduce数量.
map数量
map数量 逻辑如下
- map数量=split数量
- split数量=文件大小/split size
- splitszie=Math.max(minSize, Math.min(maxSize, blockSize))
如果不改,用默认值的话,split size就是128M.
默认参数如下
hive> set mapred.min.split.size;
mapred.min.split.size=1
hive> set mapred.max.split.size;
mapred.max.split.size=256000000
hive> set dfs.block.size;
dfs.block.size=134217728
举个例子
a) 假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数
b) 假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数
即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。
map数不是越多越好
如果有很多小文件,每个小文件被当作一个块,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,这就不合理了. 属于资源浪费.
解决这个,可以对小文件进行合并处理.
举个例子
select count(1) from emp where dt='2020-9-1'
然后这个目录下有200个1m左右的小文件,那么就需要200个task.
-- 每个map最大输入大小
set mapred.max.split.size=100000000;
--节点中可以处理的最小文件大小,100M
set mapred.min.split.size.per.node=100000000;
--机架中可以处理的最小的文件大小
set mapred.min.split.size.per.rack=100000000;
//表示执行map前对小文件进行合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
ps,这些参数都可以在hive的命令行界面直接查看!不需要找配置文件,比如
mapred.max.split.size=256000000
hive> set mapred.max.split.size;
mapred.max.split.size=256000000
hive> set mapred.min.split.size.per.node;
mapred.min.split.size.per.node=1
hive> set mapred.min.split.size.per.rack;
mapred.min.split.size.per.rack=1
hive> set hive.input.format;
hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
每个map处理128M块最好?
不是的,假设一个块128M,但是字段比较少,所以数据量非常多,这时候也是可以拆分成好几个map去处理的!
reduce数量
1 reduce的数量可以自定义,map是没有直接自定义这个设置的
你说多少就是多少
hive> set mapred.reduce.tasks;
mapred.reduce.tasks=-1
2没有自定义的话会有默认值
主要依据下面这两个参数
//每个reducer任务处理的数据量,本里中是256M
hive> set hive.exec.reducers.bytes.per.reducer;
hive.exec.reducers.bytes.per.reducer=256000000
//每个任务的最大reducer数量,这里是1009
hive> set hive.exec.reducers.max ;
hive.exec.reducers.max=1009
本例中
reducer数量=min(1009,总输入数据量/256M)
举个例子
select name,count(1) from emp where dt='2020-9-1' group by name;
如果map端输出的总大小是9G,那么reducer数量就是9000/256=35
要减少reducer个数,可以调大hive.exec.reducers.bytes.per.reducer=256000000
比如调大到500M,reducer数目就是18个
reducer数目不是越多越好
同map一样,启动reducer也要消耗资源和时间,另外,有多少reduce,就会有多少小文件生成,如果这些小文件作为下一个任务的输入,就会造成小文件过多. namenode的负担也会加重
只有一个reducer的情况设置
有些情况设置了参数也没用,就是只有一个task
1,文件大小小于hive.exec.reducers.bytes.per.reducer,这个容易理解
2用了orderby,全局排序,只能一个reduce完成
3有笛卡尔乘积
4没有group by的汇总
map数量和reducer数量有关系么?
有一点关系,因为reducer的数量是由map输出的数据的大小决定的.map输出的数据量越大,reduce的数量相应的也就越多.
针对小文件过多如何优化?
- map端开启小文件合并机制
- 减少map的数量,map输出的文件是要落地的
- 减少reduce的数量,因为reduce文件要落地的. 可以调大单个reduce处理的数据量
hive insert into比load数据慢的原因?
- 类型检查
- 多个mapreduce任务
为什么建议少用动态分区?
因为会产生大量小文件,比如一个表,不分区,就是一个文件. 按一个字段,分5个区,就是5个文件, 要是二级分区,比如依据省份分30个,依据城市分100个. 则会生成30*100=3000个小文件.用mr处理的话,就是3000个map task!
为什么少用动态分区,用时记得按distribute by分区?