MapReduce详细流程

在这里插入图片描述

在这里插入图片描述
MR整体流程:

  1. 准备待处理文本,文本相关信息(输入路径: /user/input、文件名称: ss.txt , 文件大小:200M)。

  2. 客户端获取待处理的数据信息(比如ss.txt根据块大小128M切分成块1的128M和块2的72M),根据参数配置,形成任务分配的规划。

  3. 客户端submit(),提交Job到Yarn (提交内容:Job.split-切片信息, jar包, Job.xml)。

  4. ResourceManager在NodeManager上创建ApplicationMaster,ApplicationMaster获取Job提交的描述信息并根据job信息获得需要的MapTask实例数量,向ResourceManager申请资源,ResourceManager分配资源给ApplicationMaster,ApplicationMaster启动相应数量的MapTask,一个MapTask对应处理一个分片。

  5. MapTask启动后, InputFormat的实例会创建一个RecordReader实例(默认为LineRecordReader),LineRecordReader把每一行的行偏移量作为key,把内容作为value,输出到Mapper实例的map函数中。实际上,在分块过程中,我们可能将一个数据的一行切分到两个块上,这样一个分片的最后一行的数据可能是不完整的,为了避免数据错误,LineRecordReader中在读取分片数据时,如果当前分片最后一个字符不是换行符(若是EOF则结束读取),那么会继续读取下一个分片的内容,直到读取到第一个
    换行符为止,同时在读取下一个分片数据时会跳过第一行。

  6. Mapper实例会将读入的行偏移量和行内容交由map函数进行处理,将处理结果用context.write(k,v)函数输出。

  7. OutputCollector会收集map函数处理的输出结果并写入环形缓冲区。当环形缓冲区的数据存储量达到缓冲区大小的80%(默认值,可以修改)时,会启动一个溢写线程,将数据生成溢写文件写入磁盘。但如果在此期间缓冲区被填满,写入环形缓冲区过程会阻塞直到溢写过程完成。如果MapTask的最后一批写入环形缓冲区的数据量小于缓冲区大小的80%,也会进行溢写过程。
    假若MapTask处理的分片大小小于溢写操作的最小阈值,会直接在内存中对其进行分区、排序、combine(可选)和归并排序操作。
    在溢写的过程中会触发三个子过程-分区、排序、combine(可选)。

  8. (1) 在数据溢写到磁盘之前,会先进行分区,默认的分区规则是HashPartitioner定义的(实现Partitioner接口),它会根据key的hash值取模ReduceTask数量得到的结果(相同值在同一个分区)进行分区。在不同业务场景下,我们也可以自定义Partitioner来重写分区规则。
    (2) 排序操作首先对分区进行升序排序sort,当然我们也可以通过重写数据的compartTo方法来自定义排序规则。
    (3)在分区排序后,如果我们自定义了Combiner,则会将分区内的数据进行combiner后再输出。
    拓展1: 如果我们自定义了10个分区,根据job.setNumReduceTask(num),结果如下:
    num=1 ----> 正常启动一个ReduceTask
    num(2-9) ----> 程序报错
    num>9 ----> 开启相应数量的ReduceTask,但只有10个ReduceTask工作。

  9. 溢写到文件:
    Shuffle阶段不断地进行溢写操作,直到分片数据全部都溢写完毕。
    注:Spiller阶段处理后的k-v对是分区且有序的。

  10. Merge:
    在每个Map阶段完成前,会通过多路归并算法将这些(spill file)文件归并成一个文件,即将溢写文件(spill file)拉取到磁盘文件中,按照用户定义的partitoner分区规则进行分区归并排序,这个过程就叫做Merge。Merge过程中一次默认最大能归并10个(通过自定义"mapreduce.task.io.sort.factor"参数修改)溢写文件,合并过程是一轮一轮的,假设有20个溢写文件,最终会进行3轮(20(2+10+8)->(1+10+8)->(1+1+8)->1)。
    溢写文件归并完毕后,Map将删除所有的临时溢写文件,并告知NodeManager任务已完成。

  11. merge之前会记录一共有几个溢写文件,如果溢写文件数量大于等于三个(第二次combiner过程的默认阈值,可自定义)且用户自定义了combiner方法,则会在内存中将merge的结果再次执行combiner过程,最终落地到一个大文件中。

  12. 当MapTask完成(默认为95%,可以自定义)时,就会启动相应数量的reducerTask,并告知reducerTask处理数据范围(即数据分区)。在实际场景中,资源足够的情况下,我们可以减小该默认值让ReduceTask在部分MapTask完成后提取启动。

  13. reduce阶段的shuffle也有一个内存缓冲区,它的大小要比map Task的环形缓冲区更灵活(由JVM的heapsize设置),由Copy阶段获得的数据,会存放在这个缓冲区中,同样会发生归并排序操作,当到达内存缓冲区的阈值时会发生溢写操作,这个过程会一直执行直到所有的mapTask输出结果都被复制过来为止,如果形成了多个磁盘文件还会进行Merge归并排序,归并排序后的结果不会写入到磁盘中,而是直接进行数据分组 。

  14. ReduceTask将一组一组数据传递到reduce方法的key,values值,并调用reduce()方法进行数据处理,最后通过context.write(k,v)输出。

  15. 分组补充:默认分组的规则是根据key来分组,当key为bean的时候,只有两个bean的所有成员变量相等,才会被认为是一组。我们可以通过GroupingComparator自定义分组规则来欺骗reduce,让它在两个bean的成员变量不相等的时候,也认为两个bean是相同的key,可以把一些工作提前做了,减少reduce的压力。

  16. context.write(k,v)输出数据传递给TextOutputFormat实例。TextOutputFormat实例调用getRecordWrite方法获取LineRecordWriter实例,最后利用LineRecordWriter的write(k,v)方法将数据输出到结果文件中。

若有错误之处,欢迎批评指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值