MapReduce的过程概况
Shuffle的过程是从map方法结束到reduce方法开始之前
MapTask:
1、maptask调用TextinputFormat中封装的LineRecordReader.next()方法去读取对应的切片,每次读一行。
2、并返回key(起始偏移量)和value(行内容)。
3、再调用xxMapper中的map(key,value,context)方法进行处理。
4、并返回context.write(key,value)。
5、此时OutputController.collect()会将返回的一堆(key,value)进行序列化,放到一个缓冲区里面(环形缓冲区,默认为100M)。
6、当缓冲快满的时候,会调用Spiller.spill()进行一个溢出,在溢出的过程中进行分区(key的hashcode%reducetasks)和排序(同一个区中,按key排序;运用了快速排序算法),然后生成多个溢出文件。Maptask在退出之前,将多个溢出文件合并为一个(运用了归并排序和外部排序算法)。
ReduceTask:
1、reducetask会将maptask执行完后生成的合并文件中相同分区的(key,value),合并(归并排序)到一个文件中。
2、调用xxReducer.reduce(Text key,迭代器 values,cotext),一个key调用一次对应的迭代器。
3、返回了一个context.write(key,value)。
4、TextOutputFormat中的RecordWriter.write(key,value)写到hdfs指定的目录中。
MapReduce中的排序
排序的作用
1、减小内存的使用量:
MapReduce在reduce阶段需要分组,将key相同的放在一起进行规约,为了达到该目的,有两种算法:hashmap和sort ,但hashmap算法太耗内存,而sort通过外排可对任意数据量分组,只要磁盘够大就行。map端排序是为了减轻reduce端排序的压力。
2、提高join的效率:
JOIN 操作对于有序的集合的复杂度为O(n)
,这也是排序的一个必要之处。
mapreduce中的几次排序
- 第一次:kvbuffer溢写之前会先对内存中的文件根据key和partition进行排序。方式:快排
- 第二次:所有文件都经过map方法和kvbuffer后,所有的小文件会合并成file.out文件,合并过程中会进行第二次排序,用来保证该文件有序。整个文件会根据partition分成多个块,每个块内按照key值排序。方式:归并(归并排序的方式很适合做多文件合并排序,且归并排序是具有稳定性的排序方式)。
- 第三次:reduce拉取到的文件会进行合并,此时会再次进行排序。方式:归并。
- 第四次:最后阶段:使用了堆排作最后的合并过程。