因为Hive底层就是MR,所以问题实际是MR如何确定map数量和reduce数量.
map数量
逻辑如下
如果不改,用默认值的话,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任务启动和初始化的时间远远大于逻辑处理的时间,这就不合理了. 属于资源浪费.
解决这个,可以对小文件进行合并处理.
举个例子
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
不是的,假设一个块128M,但是字段比较少,所以数据量非常多,这时候也是可以拆分成好几个map去处理的!
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个
同map一样,启动reducer也要消耗资源和时间,另外,有多少reduce,就会有多少小文件生成,如果这些小文件作为下一个任务的输入,就会造成小文件过多. namenode的负担也会加重
有些情况设置了参数也没用,就是只有一个task
1,文件大小小于hive.exec.reducers.bytes.per.reducer,这个容易理解
2用了orderby,全局排序,只能一个reduce完成
3有笛卡尔乘积
4没有group by的汇总
有一点关系,因为reducer的数量是由map输出的数据的大小决定的.map输出的数据量越大,reduce的数量相应的也就越多.
因为会产生大量小文件,比如一个表,不分区,就是一个文件. 按一个字段,分5个区,就是5个文件, 要是二级分区,比如依据省份分30个,依据城市分100个. 则会生成30*100=3000个小文件.用mr处理的话,就是3000个map task!