MapReduce是一种处理大型及超大型数据集并生成相关执行的编程模型。通俗来讲,MapReduce是一个大数据分布式计算框架,它基于google的一篇研究论文MapReduce。
MapReduce是由两个阶段组成:
- Map端
- Reduce端
而Map端和Reduce端之间有着一系列复杂的suffle(洗牌)过程
- 主要思想:分久必合
- 核心思想:"相同"的key为一组,调用一次reduce方法,方法内迭代这一组数据进行计算
概括来讲,MapReduce主要对文件进行了分片、Map、分区、排序和分组以及Reduce的工作
一、分片
在进行Map处理之前,MapReduce会根据输入的文件将它切分成多个分片(input split),才能分配给不同的MapTask去执行,每个输入分片(input split)针对一个MapTask,默认情况下,分片的大小相当于一个HDFS的block的大小,即block数 = split数 = task数。其实不然,split往往要比block大一点或者少一点。这是因为HDFS的block块按照字节切割,极有可能发生乱码。举个简单的例子:
所以输入分片(input split)存储的并非数据本身,而是一个分片长度和一个记录数据的位置的数组。
split还会对文件按行分割形成<key,value>对
- key值
这里一般是指偏移量,包括了回车所占的字符数。把每个文件按行处理,比如上面的例子中:每一行的开头字符所在位置的偏移量 ,第一行的开头偏移量自然是0,helloworld共9个偏移量,回车再算一个,第二行的开头偏移量是11,以此类推 - value值
一行数据记录
二、执行Map
Map方法是由用户自己定义的处理程序,分割好的<key,value>对交map方法进行处理,生成新的<key,value>对。每一行的字符按用户定义的格式分割,分割的每一个元素都记为1,也就是map节点的所有value都是1,key值为切割的数据段
三、分区
执行map方法输出的<key,value>对,会被写入内存缓冲区(buffer)中,
map task会将这些键值对打上标签(分区号),默认的分区器是HashPartitioner。分区策略是根据key的HashCode和reduce task的数量取模,即有几个reduce task就有几个分区。
buffer的大小默认为100M,当该缓冲区快要溢出时(默认为缓冲区大小的80%),map task会将这80%的内存锁住,然后再对这些内存中的数据进行combiner(小聚合),排序。将key值相同value值累加,按照key值排序,并将分区号相同的数据放在一起。然后会在本地文件系统中创建一个溢出文件,将该缓冲区中的数据写入这个文件。
最后map task会将这些溢出文件进行归并排序,在合并成一个大文件。相同分区号的文件放一块。
这个复杂的过程就是shuffle write过程,总的来说,就是map task将一个split切片整理成一个有分区且分区内部是有序的文件。过程中会不断地进行排序和combiner操作,目的有两个:
- 尽量减少每次写入磁盘的数据量
- 尽量减少下一阶段网络传输的数据量
四、分组
每个map task整理出一个有分区且分区内部是有序的文件,reduce task会到map端读取数据(),然后将数据写入内存中,内存满了就会溢写(比如当前系统内存为1G,该线程占用70%的内存,假设是700M当写满660M时,就会溢写)。在溢写之前会再进行排序。当把所有数据都读取完了,reduce task会将这些溢写的小文件按照key值排序,合并成有序的大文件。默认情况下是,key值相同的数据为同一组,用户也可自定义分组策略。合并成一个有序的大文件的目的是提高分组的分组效率
五、Reduce
reduce task用户自定义的reduce方法进行处理每一组数据,得到新的<key,value>对,并作为输出结果