概念
- Block: HDFS
物理上
数据切成一块一块存储 - Split :
逻辑上
对输入进行分片,不会改变物理上的存储。
MapTask
- 在MR中,每个mapTask 处理一个逻辑切片
split
的数据量 - 默认情况下,每个物理的
block
对应一个逻辑split
,每个split
对于一个mapTask
。即mapTask数=split数 - 可以通过改变
split
大小来改变mapTask
个数
FileInputFormat切片大小计算方式
//源码
//切片大小决定公式
protected long computeSplitSize(long blockSize, long minSize,
long maxSize) {
return Math.max(minSize, Math.min(maxSize, blockSize));
}
//默认最小值为1
public static long getMinSplitSize(JobContext job) {
return job.getConfiguration().getLong("mapred.min.split.size", 1L);
}
//默认最大值为Long的最大值
public static long getMaxSplitSize(JobContext context) {
return context.getConfiguration().getLong("mapred.max.split.size",
Long.MAX_VALUE);
}
更改切片大小
由上述公式可知,更改maxSize
和minSize
可以更改split
大小。
- 将
maxSize
设置的比默认blockSize
(hadoop2.x为128M)小即更改小切片大小,大小为新设置的maxSize
- 将
minSize
设置的比默认的blockSize
(haddop2.x为128M)大即可更改切片大小,大小为新设置的minSize
//设置我们的输入类型为CombineTextInputFormat
job.setInputFormatClass(CombineTextInputFormat.class);
//虚拟存储切片最大值设置4m 设置每个切片处理数据量为4M。单位long
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);
切片机制
框架默认的TextInputFormat
切片机制是对任务按文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个MapTask
,这样如果有大量小文件,就会产生大量的MapTask
,处理效率极其低下。
- 生成的切片过程包括:
虚拟存储过程
和切片过程
二部分。
CombineTextInputFormat
CombineTextInputFormat
用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个MapTask处理。(更好的选择是不要让HDFS上出现大量的小文件)
- 虚拟存储切片最大值设置
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304);// 4m
虚拟存储过程:
将输入目录下所有文件大小,依次和设置的setMaxInputSplitSize
值比较,
- 如果不大于设置的
最大值
,逻辑上划分一个块。 - 如果输入文件大于设置的
最大值
且大于两倍
,那么以最大值切割一块; - 当剩余数据大小超过设置的最大值且不大于最大值2倍,此时将文件均分成2个虚拟存储块(防止出现太小切片)。
例如setMaxInputSplitSize
值为4M
,输入文件大小为8.02M
.
- 先逻辑上分成一个
4M
。剩余的大小为4.02M
,如果按照4M
逻辑划分,就会出现0.02M
的小的虚拟存储文件,所以将剩余的4.02M
文件切分成(2.01M和2.01M)
两个文件。
切片过程:
- 判断虚拟存储的文件大小是否大于setMaxInputSplitSize值,大于等于则单独形成一个切片。
- 如果不大于则跟下一个虚拟存储文件进行合并,共同形成一个切片。
- 测试举例:有4个小文件大小分别为1.7M、5.1M、3.4M以及6.8M这四个小文件,则虚拟存储之后形成6个文件块,大小分别为:
1.7M,(2.55M、2.55M),3.4M以及(3.4M、3.4M)
最终会形成3个切片,大小分别为:
(1.7+2.55)M,(2.55+3.4)M,(3.4+3.4)M