1. MapReduce框架原理
1. InputFormat
- 定义:InputFormat负责定义输入数据的格式和如何进行切分(splitting)。它将输入数据分为多个片段(splits),每个片段会被一个MapTask处理。
- 作用:例如,
TextInputFormat
会将文本文件按行读取,而SequenceFileInputFormat
则用于处理二进制文件。
2. Input
- 定义:Input是指要被处理的原始数据,这些数据可以存储在HDFS(Hadoop分布式文件系统)中,也可以是其他支持的存储系统。
- 作用:输入数据是整个MapReduce作业的起点,所有后续处理都基于这个数据展开。
3. Mapper
- 定义:Mapper是MapReduce的一个核心组件,它负责将输入数据的每个片段进行处理,生成中间键值对(key-value pairs)。
- 工作流程:
- 接收分配给它的输入Split。
- 处理每一条记录,产生一组中间的数据(KV对)。
- 例如,在单词计数程序中,Mapper会将每个单词映射为键,并将其计数(通常为1)作为值。
4. Shuffle
- 定义:Shuffle是MapReduce框架中的一个关键步骤,负责将Mapper输出的中间数据根据键进行排序和分组。
- 作用:
- 首先,框架会将相同键的所有中间数据聚集到一起。
- 然后会把这些数据按照Reducer的数量分区,以便后续的Reducer可以并行处理。
- Shuffle阶段通常包括排序和分区的过程。
5. ReduceTask
- 定义:ReduceTask是MapReduce的第二个核心组件,负责处理从Shuffle阶段传入的中间键值对。
- 工作流程:
- 每个ReduceTask接收属于自己的中间数据。
- 它将这些数据合并并聚合,通常是对相同键的值进行处理,例如求和或计数。
- 最终,ReduceTask会生成最终的输出结果。
6. Reducer
- 定义:Reducer是执行ReduceTask的具体实现,负责接收、处理和输出数据。
- 工作流程:
- 接收来自Shuffle阶段的键值对。
- 对相同键的值进行聚合。
- 将结果输出到指定的存储位置。
7. OutputFormat
- 定义:OutputFormat定义了输出数据的格式和如何存储输出结果。
- 作用:它可以指定输出结果是写入到文本文件、序列文件或其他格式中。例如,
TextOutputFormat
会将结果写入文本文件。
8. Output
- 定义:Output是Reduce阶段最终生成的结果数据,这些数据通常会被存储在HDFS中。
- 作用:输出数据是整个MapReduce作业的最终结果,供后续处理或分析使用。
2. 数据块与数据切片
1. 数据块(Block)
在HDFS(Hadoop Distributed File System)中,数据块是物理上将数据分成一块块的单位,是HDFS存储数据的基本单位。每个数据块通常默认大小为128MB(可以根据需要进行调整),并分布在集群的不同节点上。
2. 数据切片(Input Split)
数据切片是在逻辑上对输入数据进行分块,它并不代表在磁盘上的物理切分。数据切片是MapReduce程序计算输入数据的单位,每个切片会对应启动一个MapTask。切片的数量和大小直接影响MapTask的并行度。
3. FileInputFormat 切片机制
FileInputFormat
是MapReduce中默认的输入格式,负责将输入数据划分为切片。其切片机制如下:
- 按照文件内容长度进行切片:切片的大小根据文件的字节数来决定。
- 切片大小:默认情况下,切片大小等于HDFS的Block大小。
- 针对每个文件单独切片:切片机制不考虑整个数据集,而是对每一个文件单独进行处理。
示例
假设有两个文件 file1.txt
和 file2.txt
,经过 FileInputFormat
切片机制后形成的切片信息如下:
file1.txt.split1
:0-128file1.txt.split2
:128-256file1.txt.split3
:256-320file2.txt.split1
:0-10M
4. FileInputFormat 切片大小参数配置
切片大小的计算公式
切片大小的计算公式为:
java">Math.max(minSize, Math.min(maxSize, blockSize));
mapreduce.input.fileinputformat.split.min.size
:默认值为1。mapreduce.input.fileinputformat.split.max.size
:默认值为Long.MAX_VALUE
。
默认情况下,切片大小等于Block大小。
切片大小设置
- maxSize(切片最大值):如果该参数设定小于Block大小,切片将变小,等于配置的参数值。
- minSize(切片最小值):如果该参数设定大于Block大小,切片将可能变得比Block大小更大。
5. Map和Reduce数量设置
1.Map任务数量
- Map任务数量通常由输入数据的分片数量决定。可以通过以下方式来调整:
- 调整块大小(Block Size):改变HDFS中数据块的大小。
- 调整分片大小(Split Size):通过配置参数来改变分片的逻辑划分。
2.Reduce任务数量
- Reducer的数量可以根据以下公式进行设置:
-
java">Reduce数量=min(参数2,总数据量/参数1)
- Reducer个数由Partition个数决定,Mapper生成的中间数据通过Shuffle过程进行分区,每个Partition的数据由对应的一个Reducer进行处理。因此,Reducer的数量始终大于或等于分区的数量。
- Partition:每个Mapper在处理数据时,会根据预定义的分区函数(通常是哈希函数)来决定每个输出的键值对应该被发送到哪个Reducer。这意味着在Mapper输出时,已经在逻辑上将数据分配到了相应的分区。
6. 环形缓冲区的作用
环形缓冲区是为了解决数据传输和处理效率而设计的,它在Map和Reduce阶段之间扮演着至关重要的角色。其主要作用包括:
-
内存数据传输:
- 环形缓冲区允许在内存中进行数据传输,避免频繁的磁盘IO操作,从而提升处理速度。传统的Map和Reduce之间的数据传输依赖于磁盘,这会增加延迟和降低效率。
-
数据整理与排序:
- 在多个Map任务的输出数据被送入Reduce之前,环形缓冲区能够对这些数据进行整理和排序。这使得Reduce任务可以更高效地处理数据。
-
避免重复读取与写入:
- 环形缓冲区能够减少Map和Reduce之间数据的重复读取和写入,从而节省网络带宽。
-
内存重用:
- 环形缓冲区的设计允许重复利用内存,而无需频繁申请新的内存块。这有助于规避垃圾回收机制引发的性能问题。
-
结构组成:
- 环形缓冲区包含三个部分:空闲区、数据区和索引区。初始位置叫做equator,数据从equator的左侧写入,索引从右侧写入。当数据和索引的大小达到环形缓冲区的80%时,系统会进行以下操作:
- 在原地对已写入的数据进行快速排序,并将这些排好序的数据和索引spill到磁盘上。
- 更新equator的位置,并冲洗出旧的数据和索引。
- 如果在空闲的20%区域写入数据时,之前的80%数据尚未写入磁盘,程序将会进入待处理状态,直到有足够空间可供写入。
- 环形缓冲区包含三个部分:空闲区、数据区和索引区。初始位置叫做equator,数据从equator的左侧写入,索引从右侧写入。当数据和索引的大小达到环形缓冲区的80%时,系统会进行以下操作:
7. MapReduce的三次排序
在MapReduce的过程中,共进行了三次排序:
-
Map输出排序:
- 当Map任务输出数据时,首先将数据写入环形缓冲区。达到阈值后,后台线程会将缓冲区的数据划分为相应的分区,并在每个分区内进行内排序。这一过程确保了Map阶段的输出是有序的。
-
溢写文件合并排序:
- 在Map任务完成之前,磁盘上会生成多个已分区且排好序的溢写文件。这些溢写文件的大小与缓冲区一致。合并这些文件时,仅需进行一次排序即可使最终输出文件整体有序。
-
Reduce阶段的合并排序:
- 在Reduce阶段,将多个Map任务的输出文件复制到Reduce Task中进行合并。由于这些文件已经经过二次排序,因此在合并时再次排序可以确保输出文件的有序性。