版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Mirror_w/article/details/89424314
本片博文是小二进行从源码底层所总结的,若有疑问的可以评论席留言!
小二讲堂:https://blog.csdn.net/Mirror_w
小二MapReduce源码讲解:https://blog.csdn.net/Mirror_w/article/details/89421705
一、Yarn入门介绍
1.角色介绍
YARN:解耦资源与计算
ResourceManager
主,核心
集群节点资源管理
NodeManager
与RM汇报资源
管理Container生命周期
计算框架中的角色都以Container表示
Container:【节点NM,CPU,MEM,I/O大小,启动命令】
默认NodeManager启动线程监控Container大小,超出申请资源额度,kill
支持Linux内核的Cgroup
MR :
MR-ApplicationMaster-Container
作业为单位,避免单点故障,负载到不同的节点
创建Task需要和RM申请资源(Container)
Task-Container
Client:
RM-Client:请求资源创建AM
AM-Client:与AM交互
ResourceManager(Rm):
RM是一个全局的资源管理器,负责整个系统的资源管理和分配。RM是由两个组件构成:调度器(Scheduler)和应用程序管理器(Application Manager ,ASM)。调度器根据容量、队列等限制条件(每个队列中分配一定量的资源,最多执行一定量的作业等),将系统资源分配给各个正在分配的应用程序。该调度器是一个“纯调度器”,,被分配资源后它不在从事任何与具体该应用程序相关的工作。应用程序管理器负责整个系统中的所有的应用程序,包括应用程序提交、与调度器协商资源以启动ApplicaitonMaster、监控ApplicationMaster的运行状态并负责在失败时重启它们。
Application Master(AM):用户提交的每一个程序都包含一个AM主要功能有:
1.与RM调度器协商以获取资源(用Container表示),
2、将得到的任务进一步分配给内部的任务(资源的二次分配).
3、与NameNode进行通信,用于启动或停止任务。
4、监控所有任务的运行状态,并在任务运行失败时,重新为任务申请资源以重启任务。
5、当前YARN自带了两个AM实现,一个是用于演示AM编写方法的实例程序distributedshell,它可以申请一定数目的Container以并行运行一个Shell命令或者Shell脚本;另一个是运行MapReduce应用程序的AM—MRAppMaster;
注意:RM只负责监控AM,在AM重启失败时候启动他们,RM不负责AM内部的任务容错,这个由AM来完成。
二、作业流程
JobSubmitter提交作业的流程:
1.向resourcemanager进行申请一个新的Application ID 作为MapReduce作业ID
2.进行检查作业,如果作业的输出路径没有指定或者已经存在,则不提交作业,mapReduce程序抛出异常
3.进行计算作业输入数据的切片(比如输入路径没有设置或者输入路径不存在),如果不能计算切片则不提交作业,抛出异常
4.拷贝执行作业所需要的资源到HDFS共享文件系统中,并且拷贝到以作业ID为名称目录下。这些资源包括作业的jar包、配置文件、切片信息。作业的jar包有很多的副本数量,默认是10(可以设置),可以方便当nodemanager进行执行作业中的任务,可以有很多的作业任务去运行。
5.然后进行调用resourceManeger中的submitApplication 方法进行提交任务。
6.YARN会分配一个容器,resourceManger会根据容器所在节点上的nodemanager进行分配一个ApplicationMaster进程
7.而ApplicationMaster的主入口类是MapReduceApplicationMaster,而MRAppMaster进程会从上传到HDFS中获取上传的计算好的切片信息,根据切片信息,给每一个切片分配对应的Map任务对象和Reduce任务对象。
8.ApplicationMaster会向resourceManager进行申请资源,根据Map任务和reduce任务申请容器。申请过程中为Map任务申请会优先进行,当Map任务完成达到5%时,进行为reduce任务申请资源。reduce会运行于集群中的任意位置,而map任务会受本地读取的限制,由于要遵循“计算向数据移动”的规则。
9.一旦resourcemanager为任务分配了资源容器,则ApplicationMaster会和nodemanager进行通信进行启动容器,进行任务的执行。
10,任务要进行是通过一个java application类执行的,而java application 的入口类是YARNChild,在他开始执行任务之前,首先会加载所需要的资源包括任务jar包、配置文件以及分布式缓存中的其他共享文件,最后它开始执行map任务和reduce任务。
11.当作业完成时,会通知ApplicationMaster ,Application Master会将任务的状态改为“successfully”,向客户端通知完成信息,客户端的waitforComplietion方法返回状态信息。
12,作业完成后,application master会将所在容器中的作业销毁工作状态,中间结果删除。作业的信息被历史服务器存档以备后续查看。
三、作业流程分布解析-----重点理解
1.Job初始化过程
1). 当resourceManager收到了submitApplication()方法的调用通知后,scheduler开始分container,随之ResourceManager发送ApplicationMaster进程告知每个NodeManager
2). 由applicationMaster决定如何运行tasks,如果job数据量比较小,applivation便选择将task运行在一个JVM中。那么如何决定job的大小呢?当一个job中的mappers数量小于10个时或者只有一个reduce或者说读取文件的大小小于一个block时,可通过配置文件配置(mapreduce.job.ubertask.maxmaps,mapreduce.job.ubertask.maxreduces以及mapreduce.job.ubertask.maxbytes )
3). 在task任务运行之前,applicationMaster将会调用setupJob()方法,随之创建输出路径,这样就可以解释,在运行一个mr-job时,mapper一开始报错都会有输出路径的创建。
2.Task任务的分配
当applicatioinMaster请求resourceManager,启动container容器去执行map任务和reduce任务时,map task任务执行的优先级比reduce task高,Map task首先会进行执行,当Map task执行到5%时,reduce task会开始执行。
运行map task 和reduce task 是需要cpu 资源的,默认情况下系统会给map task和reduce task 分配 1024MB与一个核,当然也可以去配置(mapreduce.map.memory.mb,mapreduce.reduce.memory.mb,mapreduce.map.cpu.vcores,mapreduce.reduce.reduce.cpu.vcores)
3.Task任务的执行
1).这时task已经被applicationMaster分配到一个Container容器中, 然后由applicationMaster通知resourceManager去启动container,当container启动时,这个task 会被一个主函数为YarnChild的java application运行,但在运行之前,会进行定位task任务需要的jar包、配置文件以及加载到缓存中的文件信息。
2)YarnChild运行于一个专属的JVM中,任何一个map task和reduce task出现问题都不会影响整个nodemanager的hang或者crash.
3)每个task都可以运行在相同的JVM task中完成,完成后会将结果写入HDFS的一个文件中。
4.运行进度与状态
MapReduce是一个运行时间较长的批处理过程,可能是几分钟、几小时、几天都有可能。那么在运行过程中监控就是非常重要了,每个task任务的执行包含着不同的运行状态分别有:running、successfully、completed、failed状态。以及value的计数器、状态信息以及描述信息(这些描述信息可以在代码中进行打印),那么客户端怎么知道这些信息呢?这些信息又是怎么和客户端进行通信的呢?
答案:当一个task运行的时候,会记录它的运行记录,记录task运行的完成比例。对于map任务将会记录它完成的百分比,对于reduce的记录会涉及复杂的信息记录,但是最重要的是,系统还是会估计reduce task完成的比例。当map或者reduce 任务执行的时候,其子进程和applicatioin保持心跳,每隔3秒子进程会向applicatioin进行交互。
5.Job的完成
当job任务完成的时候,applicationMaster会收到一个job完成的通知-,然后改变job的状态为successfully。最后将运行task的container容器进行清空。
四、Shuffle----重点
从map的输出到reduce的输入的过程被称之为shuffle,map端到reduce端的数据一定是通过key排序的。
1.The Map Side
首先map任务的output过程是一个环形缓冲区中进行的,缓冲区的大小为100M(可通过修改配置项mpareduce.task.io.sort.mb进行修改),当写入内存的数据达到一定比例,默认80%,(可通过mapreduce.map.sort.spill.percent配置项修改)便开始溢写到磁盘。注意在溢写磁盘之前会有sort排序和combiner(可能会有,下面会说)。
在写入磁盘磁盘之前,会将数据写入分区中,这个分区是通过对每个数据的key的hashcode值对reduce个数,进行分区的(源码中计算公式:key.hashCode()%numReduceTask),后台线程会在内存中通过key进行排序,然后通过配置文件进行获取combiner的方法,如果设置了combiner的方法,则就会partition中的数据进行排序,而在进行排序的时候首先会判断环形缓冲区写入的文件,如果写入的文件小于3那么即使设置了combiner也不是被调用,当大于3是才会被调用。
如果有大量的文件进行了溢写,那么使用combiner进行压缩,那么会大大减少磁盘IO和网络传输的开销。(配置参数mapreduce.map .output.compress 设置为true,如果使用第三方压缩jar,可通过mapreduce.map.output.compress.codec进行设置)。
最后这些partition中文件会通过Http发送给reduce。
2、The Reduce Side
首先map都将每个结果写入本地磁盘中,现在reduce需要将map结果通过http拉取传输,这里要注意要等到所有map任务结束之后,reduce才会对map的结果进行拷贝,这里通过默认是5个线程进行拉取的(可以通过配置进行设置mapreduce.reduce.shuffle.parallelcopies)。
那么reduce又是怎么知道从哪些节点上进行拉取数据呢?又怎么知道哪些节点上的数据完成了呢?
当所有map任务结束后,applicationMaster通过心跳机制,又它知道map输出的结果和节点信息,所以reduce在拉取数据的时候必须去请求ApplicationMaster,去找到map输出的结果。
map的结果会被拷贝到reduce task的JVM进程(内存大小可在mapreduce.reduce.shuffle.input.buffer.percent中设置),如果键数据拷入到内存中不够用,那么会溢写到磁盘上,当内存缓冲区大小达到阈值(可通过mapreduce.reduce.shuffle.merge.percent设置)或者map输出的结果文件过多时(这里的输出结果文件过多有可能是正常的,有可能是不正常的比如文件过多时没有进行combine),将会合并写入磁盘中。
要注意当文件过多时,需要在map端进行combiner压缩,当数据被压缩后reduce拉取到内存中时,首先要在内存中进行解压缩,以便后续的处理。合并最终文件的数量可通过mapreduce.task.io.sort.factor进行配置。
看完之后一定要看源码:
源码:https://blog.csdn.net/Mirror_w/article/details/89420501
小二推荐:https://blog.csdn.net/Mirror_w/article/details/89301229
————————————————
版权声明:本文为CSDN博主「数据小二」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Mirror_w/article/details/89424314