MapReduce以及shuffle的工作流程机制

1、MapTask工作机制

1.png
提交阶段
1、首先准备待处理的文本
2、在提交之前会先获得待处理的数据信息,然后根据参数的配置,形成一个任务分配的规划
3、在提交信息的时候会判断运行环境是本地还是yarn,如果是yarn的环境会把切片信息,配置文件信息以及当前的MapReduce的jar包提交上去
4、当提交完成以后,yarn会有一个MrApplicationMaster专门接受请求信息,根据切片计算出需要开启多少个MapTask任务进程

Read阶段
5、通过inputFormat读取数据,在读取数据的时候会创建RecorderReader对象(默认使用的是TextInputFormat,使用的是lineRecorderReader按行读取,将当前行的偏移量作为key,整行的数据作为value进行封装)对key和value进行封装,封装完了以后传递给Map方法

Map阶段
6、此时map(K,V)就会进行业务逻辑运算

Collect阶段
7、当map方法处理完了以后通过context.write写给了环形缓冲区。环形缓冲区属于内存,默认空间为100M,环形缓冲区分成两部分,一部分是存储元数据信息,另一部分存储的是map传递过来的实际数据(元数据中保存着实际数据的索引,分区信息,key起始位置,value的起始位置等),当在环形缓冲区中存储的数据达到80%的时候开始反向写,此时一遍向硬盘中刷写数据,一遍接受map传递过来的数据信
8、如果有需要可以对数据进行分区排序,在溢出过程及合并的过程中,都要调用Partitioner进行分区和针对key进行区内排序

溢写阶段
9、在环形缓冲区达到80%以后溢写到磁盘文件,溢写到磁盘上的文件应该已经分好区并且已经是在区内排好序的。溢写可以多次,所以在溢写完成以后会按照分区做一个Merge的归并排序

Combin阶段
10、这个虽然叫combine阶段,但是和前面的combine不同,这个是将多次溢写产生的多个溢写文件进行归并排序。即将多个溢写文件合并成一个文件并且做好排序

  • Map阶段:该节点主要是将解析出的key/value交给用户编写map()函数处理,并产生一系列新的key/value
  • Collect收集阶段:在用户编写map()函数中,当数据处理完成后,一般会调用OutputCollector.collect()输出结果。在该函数内部,它会将生成的key/value分区(调用Partitioner),并写入一个环形内存缓冲区中
  • Spill阶段:即“溢写”,当环形缓冲区满后,MapReduce会将数据写到本地磁盘上,生成一个临时文件。需要注意的是,将数据写入本地磁盘之前,先要对数据进行一次本地排序,并在必要时对数据进行合并、压缩等操作

    • 溢写阶段详情:

      • 步骤1:利用快速排序算法对缓存区内的数据进行排序,排序方式是,先按照分区编号Partition进行排序,然后按照key进行排序。这样,经过排序后,数据以分区为单位聚集在一起,且同一分区内所有数据按照key有序
      • 步骤2:按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件output/spillN.out(N表示当前溢写次数)中。如果用户设置了Combiner,则写入文件之前,对每个分区中的数据进行一次聚集操作
      • 步骤3:将分区数据的元信息写到内存索引数据结构SpillRecord中,其中每个分区的元信息包括在临时文件中的偏移量、压缩前数据大小和压缩后数据大小。如果当前内存索引大小超过1MB,则将内存索引写到文件output/spillN.out.index中
  • Combine阶段:当所有数据处理完成后,MapTask对所有临时文件进行一次合并,以确保最终只会生成一个数据文件

        当所有数据处理完后,MapTask会将所有临时文件合并成一个大文件,并保存到文件output/file.out中,同时生成相应的索引文件output/file.out.index。
        在进行文件合并过程中,MapTask以分区为单位进行合并。对于某个分区,它将采用多轮递归合并的方式。每轮合并io.sort.factor(默认10)个文件,并将产生的文件重新加入待合并列表中,对文件排序后,重复以上过程,直到最终得到一个大文件。
        让每个MapTask最终只生成一个数据文件,可避免同时打开大量文件和同时读取大量小文件产生的随机读取带来的开销

2、ReduceTask工作机制

2.png

11、mapTask进行Merge归并排序以后输出数据放在磁盘上,输出数据的位置在tmp/hadoop-Administrator/mapred/local/localRunner/Administrator下
12、reduce会根据当前分区的个数来决定开启多少个ReduceTask进程

Copy阶段
13、ReduceTask根据自己的分区号主动的将mapTask的内容拷贝到reduce中。同样在拷贝的时候也是拷贝到内存中,如果内存不够的话会溢写到磁盘上

Sort、Merge阶段
14、ReduceTask会将这些文件再进行合并(归并排序),在合并的时候已经排好序了

Reduce阶段
15、使用reduce的方法读取数据(相同的key执行一次)

        如果默认比较规则方法不满足需求,可以自定义分组(继承GroupingComparator类),在reduce方法之前进行,这样reduce方法在读取数据的时候可以一次读取自定义分组的一组数据。当reduceTask方法完成以后,默认使用TextOutPutFormat方法向磁盘上刷写文件。

3、 shuffle机制

Map方法之后,reduce方法之前的数据处理过程称之为shuffle

3.png

        环形缓冲区需要设计成两部分,一部分是元数据,另外一部分是存储实际的值,这样做的好处:如果在这个时候做分区或者排序的时候,就只需要对元数据做就可以了,而不需要对实际存储数据做改动

  1. map方法在处理完数据以后传递给环形缓冲区,环形缓冲区属于内存,默认空间为100M,环形缓冲区分成两部分,一部分是存储元数据信息,另一部分存储的是map传递过来的实际数据(元数据中保存着实际数据的索引,分区信息,key起始位置,value的起始位置等)
  2. 当在环形缓冲区中存储的数据达到80%的时候开始向磁盘开始溢写,在保存到磁盘上之前会根据自己的设定将环形缓冲区中的内容进行分区,并且对分区的内容做排序,然后溢写到磁盘上
  3. 在溢写的时候可以做合并(例如出现3次<a,1>,合并会变成<a,3>),combiner是可选流程,且并不属于reduce的范围之内,其实是独立于MapReduce的。
  4. 在向磁盘上溢写的过程中可能会出现多次溢写,过程类似,所以会生成多个溢写文件,在溢写文件中存储溢写索引(split.index),以及溢写溢写的存储文件。会在reduce处理之前将溢写文件进行归并
  5. 在进行分区归并以后也可以再进行一次combiner(例如分区hexo1出现了<a,3>,分区2出现了<a,5>,在合并以后会变成<a,8>,在进行合并以后可以减轻reduce的工作量),然后溢写到磁盘上
  6. 在map阶段结束以后就会进入reduce阶段,ReduceTask根据自己的分区号主动的将mapTask的内容拷贝到内存缓冲中,在内存满了以后就会溢写到磁盘,并对每个map来的数据进行归并排序,在按照相同的key进行分组(继承WritableComparator重写compara方法指定分组规则)
  7. 在分组以后,根据不同的分组将数据传递给reduce
阅读 303

推荐阅读