MR作业提交过程部分转载于小北觅https://www.jianshu.com/p/d1e7b4ff3810
之前看了YARN权威指南后总结了YARN作业提交流程(https://blog.csdn.net/Ahuuua/article/details/90410512),但还是不够清晰详细,所以转载这篇文章以便日后学习用。
-
MR作业提交过程
提交过程按这个图来,
1.
Job的submit()方法创建一个内 部的JobSummiter 实例,调用该实例submitJobInternal()方法。
提交作业后,waitForCompletion()每秒轮询作业的进度,如果发现自上次报告后有改变,便把进度报告到控制台。
作业完成后,如果成功,就显示作业计数器;如果失败,则导致作业失败的错误被记录到控制台。
2.
向ResourceManager请求一个作业ID(applicationID)。
3.
a.检查输出(output)目录是否正确。若未指定或未被创建,则抛出错误。
b.计算输入(input)的分片(splits)。如果分片不能被计算(例如,输入路径不正确),该作业不会被提交且一个错误被抛出给 MapReduce 程序。
c.拷贝运行job 需要的jar包、配置文件以及计算的输入分片(split)到HDFS中的一个以作业ID命名的文件中。
4.
在ResourceManager中调用submitAppliction()方法,执行job。
5.
当ResourceManager收到了submitApplication()方法的调用通知后,scheduler开始分配container(Containter0)。
Containter0作为ApplicationMaster的容器。
ResourceManager联系相应的NodeManager并启动ApplicationMaster。
6.
初始化作业,建立ApplicationMaster的RPC端口和用于跟踪的URL,用来监控应用程序状态。
7.
获取输入分片。
由applicationMaster决定如何运行tasks,如果job数据量比较小,applicationMaster便选择将这些任务运行再自身的JVM中。
这种情况发生的前提是,application master 判断分配和运行任务在一个新的容器上的开销超过并行运行这些任务所带来的回报,据此和顺序地在同一个节点上运行这些任务进行比较。
这样的作业被称为 uberized,或者作为一个 uber 任务运行。
一个小的作业具有哪些资格?默认的情况下,它拥有少于 10 个 mapper,只有一个 reducer,且单个输入的 size 小于 HDFS block 的。(注意,这些值可以通过 mapreduce.job.ubertask.maxmaps, mapreduce.job.ubertask.maxreduces, mapreduce.job.ubertask.maxbytes 进行设置)。Uber 任务必须显示地将 mapreduce.job.ubertask.enable 设置为 true。
在运行tasks之前,applicationMaster将会调用setupJob()方法,它为作业创建最终的输出目录和任务输出创建临时工作空间。
8.
如果作业没有资格作为 uber 任务来运行,接下来applicationMaster向ResourceManager请求containers用于执行map与reduce的tasks。
这里map task的优先级要高于reduce task,当所有的map tasks结束后,随之进行sort(这里是shuffle过程后面再说),最后进行reduce task的开始。(这里有一点,当map tasks执行了百分之5%的时候,将会请求reduce)运行tasks的是需要消耗内存与CPU资源的,默认情况下,map和reduce的task资源分配为1024MB与一个核,(可修改运行的最小与最大参数配置,mapreduce.map.memory.mb, mapreduce.reduce.memory.mb, mapreduce.map.cpu.vcores, mapreduce.reduce.reduce.cpu.vcores.)
reduce 任务可以运行在集群中的任何地方,但是 map 任务的请求有数据本地约束(data locality constraint),调度器尽力遵守该约束(try to honor)。在最佳的情况下,任务的输入是数据本地的(data local)-- 也就是任务运行在分片驻留的节点上。或者,任务可能是机架本地的(rack local),也就是和分片在同一个机架上,而不是同一个节点上。有一些任务既不是数据本地的也不是机架本地的,该任务从不同机架上面获取数据而不是任务本身运行的节点上。对于特定的作业,你可以通过查看作业计数器(job's counters)来确定任务的位置级别(locality level)。
9.
(1)task分配到container后,ApplicationMaster将ResourceManager分配的Container告知NodeManager。
(2)NodeManager启动Container。
(ApplicationMaster将ResourceManager分配的Container告知NodeManager以便ApplicationMaster使用。)
10.
这个task将会被一个主函数为YarnChild的java application运行,但在运行task之前,首先定位task需要的jar包、配置文件以及加载在缓存中的文件(retrieve job resources)。
task完成后,将完成处理的数据写入临时文件中。
YarnChild运行于一个专属的JVM中,所以任何一个map或reduce任务出现问题,都不会影响整个nodemanager,比如造成nodemanager的崩溃或者挂起。
11.
运行 map 或者 reduce 任务。
job完成后,applicationMaster会收到一个job完成的通知,随后改变job的状态为successful。
随后,applicationMaster与task containers被清空。
MR计算流程部分转载于想艳阳天里的你https://blog.csdn.net/weixin_43563705/article/details/103069225
参考:https://blog.csdn.net/weixin_43563705/article/details/103069225
https://www.cnblogs.com/ahu-lichang/p/6645074.html
-
MR计算流程
先上图,整体过程如下图所示。
1.InputFormat
InputFormat:在HDFS中读取要进行计算的数据
输出给Split
2.Split
Split:将数据进行分片,切分成多个任务
Hadoop2.x block(128M) Hadoop1.x block(64M)
输出给Split("\n")
3.Split("\n")
Split("\n"):将切分后的数据转换成key-value进行输出,<k1,v1>
key:每一行行首字母偏移量(起始偏移量)
value:每一行数据(行文本内容)
eg.<0,hello you> <10,hello me>
输出给Map
4.Map
调用自己编写的map逻辑将,输入键值对<k1,v1>变成<k2,v2>。
在这里每个键值对<k1,v1>都会调用一次map函数。
Map的输出是key-value的list。
eg.<hello,1> <you,1> <hello,1> <me,1>
输出给Shuffle(partition)
5.parition分区
parition:对<k2,v2>的list进行分区。
分区的规则是针对k2进行的,比如说k2如果是省份的话,那么就可以按照不同的省份进行分区,同一个省份的k2划分到一个区。
注意:默认分区的类是HashPartitioner类,这个类默认只分为一个区,因此Reducer任务的数量默认也是1.
输出给Sort
6.Sort排序
Sort:对每个分区内的数据进行排序,对每个分区中的键值对进行排序。
注意:所谓排序是针对k2进行的,v2是不参与排序的,如果要让v2也参与排序,需要自定义排序的类。
eg.<hello,1> <hello,1> <me,1> <you,1>
输出给Group
7.Group分组
Group:将相同key的值提取出来作为唯一的key,将相同key对应对应的value提取出来组成一个value的list。
例如,在WordCount程序中的<hello,{1,1}>执行的就是这个步骤,但是要注意:分组也是针对key进行的,经过分组完之后,就得到了我们熟悉的键值对<k2,v2s>。
eg.<hello,{1,1}> <me,{1}> <you,{1}>
输出给Combiner
8.Combiner
Combiner:在Map端进行局部聚合。
这一阶段是可选的,目的是为了减少网络带宽开销。
eg.<hello,{2}> <me,{1}> <you,{1}>
输出给Sort&Merge
9.Sort&Merge
sort+merge:对多个Mapper任务的输出,按照不同的分区,通过网络拷贝到不同的Reducer节点上进行处理,将数据按照分区拷贝到不同的Reducer节点之后,对多个Mapper任务的输出再进行排序,合并。例如:在WordCount程序中,若一个Mapper任务输出了<hello,{1,1}>,另外一个Mapper任务的输出为<hello,{1,1,1}>,经过在次合并之后变为<hello,{1,1,1,1,1}>。
我在文章https://blog.csdn.net/Ahuuua/article/details/105901472中画出了该步骤的流程。
输出给Reduce
10.Reduce
Reduce:根据业务需求对传入的数据进行汇总计算
调用自己的reduce逻辑,将键值对<k2,v2s>变为<k3,v3>.在这里注意:每一个键值对<k2,v2s>都会调用一次reduce函数。
输出给outputFormat
11.OutputFormat
outputFormat:将最终结果输出。
shuffle过程应该是5-9
详细的过程可参考: