目录
- 切片与 MapTask 并行度
- MapTask 并行度决定机制
- InputFormat如何切片
- 计算切片大小的公式
- 获取切片信息API
- 总结:InputFormat切片机制
- TextInputFormat
- CombineTextInputFormat切片机制
作用:文件切片,提交Job
切片与 MapTask 并行度
MapTask的并行度决定 Map 阶段的任务处理并发度,进而影响到整个 Job 的处理速度。
MapTask 并行度决定机制
数据块:Block 是 HDFS 物理上把数据分成一块一块。数据块是 HDFS存储数据单位。
数据切片:数据切片只是在逻辑上对输入进行分片,并不会在磁盘上将其切分成片进行存储。数据切片是 MapReduce 程序计算输入数据的单位,一个切片会对应启动一个 MapTask。
InputFormat如何切片
- 程序先找到你数据存储的目录。
- 开始遍历处理(规划切片)目录下的每一个文件
- 遍历第一个文件ss.txt
a)获取文件大小fs.sizeOf(ss.txt)
b)计算切片大小
c)默认情况下,切片大小=blocksize
d)开始切,形成第1个切片:ss.txt—0:128M 第2个切片ss.txt—128:256M 第3个切片ss.txt—256M:300M
(每次切片时,都要判断切完剩下的部分是否大于块的1.1倍,不大于1.1倍就划分一块切片)
e)将切片信息写到一个切片规划文件中
f)整个切片的核心过程在getSplit()方法中完成
g)InputSplit只记录了切片的元数据信息,比如起始位置、长度以及所在的节点列表等。
4. 提交切片规划文件到YARN上,YARN上的MrAppMaster就可以根据切片规划文件计算开启MapTask个数。
计算切片大小的公式
Math.max(minSize, Math.min(maxSize, blockSize));
mapreduce.input.fileinputformat.split.minsize=1 默认值为1
mapreduce.input.fileinputformat.split.maxsize= Long.MAXValue 默认值Long.MAXValue
因此,默认情况下,切片大小=blocksize。
获取切片信息API
// 获取切片的文件名称
String name = inputSplit.getPath().getName();
// 根据文件类型获取切片信息
FileSplit inputSplit = (FileSplit) context.getInputSplit();
总结:InputFormat切片机制
- 简单地按照文件的内容长度进行切片
- 切片大小,默认等于Block大小
- 切片时不考虑数据集整体,而是逐个针对每一个文件单独切片
TextInputFormat
FileInputFormat 常见的接口实现类包括:TextInputFormat、KeyValueTextInputFormat、NLineInputFormat、CombineTextInputFormat 和自定义 InputFormat 等。
因为MapReduce 要针对不同的数据类型去读取。
原理
TextInputFormat 是默认的 FileInputFormat 实现类。按行读取每条记录。
键是存储该行在整个文件中的起始字节偏移量, LongWritable 类型。
值是这行的内容,不包括任何行终止符(换行符和回符)
CombineTextInputFormat切片机制
TextInputFormat缺点
框架默认的 TextInputFormat 切片机制是对任务按文件规划切片,不管文件多小,都会是一个单独的切片,都会交给一个MapTask,这样如果有大量小文件,就会产生大量的MapTask,处理效率极其低下。
应用场景
CombineTextInputFormat用于小文件过多的场景,它可以将多个小文件从逻辑上规划到一个切片中,这样,多个小文件就可以交给一个 MapTask 处理。
虚拟存储切片最大值设置
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值。
切片机制
生成切片过程包括:虚拟存储过程和切片过程二部分。
虚拟存储过程
- 将输入目录下所有文件大小,依次和设置的setMaxInputSplitSize
值比较,如果不大于设置的最大值,逻辑上划分一个块。 - 如果输入文件大于设置的最大值且大于两倍,那么以最大值切割1块(不是只切成一块的意思,而是后续继续切)
- 当剩余数据大小超过设置的最大值且不大于最大值 2 倍,此时 将文件均分成 2 个虚拟存储块(防止出现太小切片)。
例如 setMaxInputSplitSize 值为 4M,输入文件大小为 8.02M,则先逻辑上分成一个4M。(条件2)
剩余的大小为 4.02M,如果按照 4M 逻辑划分,就会出现 0.02M 的小的虚拟存储文件,所以将剩余的 4.02M 文件切分成(2.01M 和 2.01M)两个文件。(条件3)
切片过程
- 判断虚拟存储的文件大小是否大于 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
代码
如果不做任何处理,默认切片为4
在Driver中增加如下代码
// 如果不设置 InputFormat,它默认用的是 TextInputFormat.class
job.setInputFormatClass(CombineTextInputFormat.class);
//虚拟存储切片最大值设置 4m
CombineTextInputFormat.setMaxInputSplitSize(job, 4194304); //设置为4M
则运行结果为3个切片