关于Yarn源码的那些事(一)

作为新一代的资源调度统一框架,Yarn(Yet Another Resource Negotiator),在不断的完善过程中,其用途已经绝不限于Hadoop的生态圈内,业界中,流式计算如Storm,Spark均可以在一定的封装之后,运行于Yarn上,但是,就目前的发展进度来说,Yarn的基本框架,还是没有彻底的变化。

就Yarn的整体架构来说,ResourceManager作为资源调度框架的老大,集中管理集群中的资源,其手下有一堆小弟,这群小弟叫做NodeManager,听起来也很好懂,节点管理器,想想,Yarn实际上还是Master/Slave的架构,一群NodeManager,拥护着老大ResourceManager,好不热闹。

简单来说,Yarn就是分担着不同角色的几台机器组合起来,非常简单。

但是,问题来了。

1:独立的机器是不可能完成分布式框架运作的,必须完成通信,那么,ResourceManager与NodeManager是如何完成通信的?通信过程中传递的都是什么样的消息?

2:延续第一点,消息传递的格式是网络传输的二进制流毫无疑问,但是是什么样的二进制流?或者说,采用了什么样的序列化机制?这也是Yarn相对于MR1的一大改进。

3:我们平时写了一个MapReduce程序,其到底是如何提交到Yarn集群上运行起来的,这个叫做JobClient的中间商,担负了什么样的角色?

不想不知道,一想吓一跳,其中很多的圈圈绕绕,我还没有完全看得通透。

带着这些问题,一点点琢磨。

在MR1中,集群中当之无愧的老大是JobTracker,其不仅负责整个集群的资源调度管理,而且还要承担起进程管理的职责,需要监督每个应用的运行状况。

很明显,这就带来了问题。

  1. 因为JobTracker毕竟是单机的,如此大的消耗,肯定是吃不消的,这就是MR1的瓶颈所在。
  2. 扩展性不强,因为资源管理和作业控制强制绑定在一起,我们的MR1就只能运行MapReduce的程序,其他的程序,是跑步起来的,至少目前来说是这样的。
  3. 在设计之初,考虑到MapTask和ReduceTask在资源占用上大不相同,所以分别为Map任务和Reduce任务分配了Map的slot和Reduce的slot,看似合理,但实际上,我们程序运行的时候,会出现资源的空置情况,MapTask运行的时候,诸多的ReduceSlot处于闲置,而Reduce任务运行的时候,Map Slot又都尸位素餐,很明显这绝对不合理

或者从更深一层的角度来说,作业控制和资源调度二者,本身就不应该绑定在一起,从更合理的层面来说,资源调度管理的是集群中所有的计算资源,如CPU,IO,网络宽带等资源,不应该让他们牵涉到作业控制之中;这样分为两层,大家其乐融融,互不干扰,岂不妙哉。

这样的思想下,资源调度管理被拆分出来,做成了通用的模块,而其他程序,也可以完美地利用底层的资源框架,优哉游哉地运行自己的程序,完全不用考虑底层的事情,再好不过了。

这样做的好处在于:

  1. 对于大数据作业的编写人员来说,只需要考虑如何优化自己的作业即可,不用担心底层资源分配优化的问题
  2. 通用的资源调度和管理框架,可以合理地运行更多的作业。

在这样的思想推动下,Yarn应运而生,而且蓬勃发展起来。


盗图一张,来自于Hadoop技术内幕,董老师的书:《深入解析YARN架构设计与实现原理》,有兴趣的可以认真看下这本书。

就这章基本的架构图来说,为Yarn添加几个名词:

1:ApplicationMaster:

对于MR1来说,我们编写的MapReduce程序,都是JobClient提交给集群,然后由JobTracker负责对作业的运行情况进行监督和管理。

这就是我们上面提到的,JobTracker一边负责给提交的作业寻找资源,一边还要监督整个作业的运行状况。

而在Yarn中,我们把JobTracker的作业管理拆分出来,针对每一个作业都有一个作业管理器,叫做ApplicationMaster,对于用户来说,提交的每一个作业,都有一个AM,在2.0以后版本的Hadoop中,自带一个MRAppMaster,所以我们平时在使用MapReduce作业的时候,没有意识到这个Master的存在,但却一直在用着的。

说下ApplicationMaster的功能吧:

  1. 与RM调度器协商以获取资源:ResourceManager作为资源调度框架的老大,最清楚整个集群的资源目前是个什么状况,而NodeManager互相之间是没有通信的,它们统一地,定时地告诉老大自己目前的战斗力,而这个老大,负责与ApplicationMaster进行沟通,告诉客户(ApplicationMaster)自己的资源,两个人琢磨琢磨,能不能给出足够的资源;所以,ApplicationMaster启动之后的第一件事情,就是先去拿资源;这里有个问题,启动之前呢?或者说ApplicationMaster是怎么启动的(潜藏问题1)?
  2. 与NM通信以启动/停止任务:来自于董老师书中的说法,我觉得很好,怎么表示自己占用了这么多的资源呢?毫无疑问,那就是把任务启动起来,自然就占用了对应的资源,而如果任务执行完毕了,那就释放获取到的资源,在某些情况下,ApplicationMaster也可以自行释放自己占用的资源。
  3. 监控所有的任务运行状态,并且在任务运行失败时,重新为任务申请资源以重启任务:这个不予赘述了。
  4. 将得到的任务进一步分配给内部的任务(后文再说)。

大家能看到,这里面一直提到了资源,这是个有点虚的词汇,而在Yarn中,有一个词来描述,叫做Container。

2:Container

作为Yarn中的资源抽象,其描述了某个节点上的多维度资源,包括内存,CPU,磁盘,网络等,当AM向RM申请资源时候,RM为AM返回的资源就是用Container来表示的,Yarn会为每个任务分配一个Container,该任务只能使用该Container中描述的资源。这里必须注意,Container和Slot是不同的,是一个动态资源划分的单位。

其实,这部分更应该从源码角度来分析比较合适:源码在org.apache.hadoop.yarn.api.records中:

简单说下:

@Private
	@Unstable
	public static Container newInstance(ContainerId containerId, NodeId nodeId,
			String nodeHttpAddress, Resource resource, Priority priority,
			Token containerToken) {
		Container container = Records.newRecord(Container.class);
		container.setId(containerId);
		container.setNodeId(nodeId);
		container.setNodeHttpAddress(nodeHttpAddress);
		container.setResource(resource);
		container.setPriority(priority);
		container.setContainerToken(containerToken);
		return container;
	}

代码来自于Hadoop-2.6.5版本,Container的初始化,就是用该方法实现的,可以看到Container的几个主要成员变量:id是Container在整个集群中唯一的标识;NodeId是Container所在的节点标识,通过这个值,Application可以联系到对应的NM,拉取到RM分配给自己的资源;其他不多说,大家可以参见代码,注释非常详细。

这里说下其中的Resource:

@Public
	@Stable
	public static Resource newInstance(int memory, int vCores) {
		Resource resource = Records.newRecord(Resource.class);
		resource.setMemory(memory);
		resource.setVirtualCores(vCores);
		return resource;
	}

就2.6.5版本来说,只支持内存和虚拟核数的分配,就是内存资源和CPU资源的分配,这里可以看出来,Container是一个完全动态化的概念,也可以看出来其跟Map Slot和Reduce Slot的区别。

其实这里还存在一个问题,我们提交作业时候指定的资源参数,是否会传到这里?如果提交的时候,没有指定资源量,那默认是怎么分配Container的?

本文先不介绍这些更细致的东西,后续再说。

本文写作时候,Hadoop已经到了3.1.0的版本,可以指定更多的资源:

public static final String MEMORY_URI = "memory-mb";
public static final String VCORES_URI = "vcores";
public static final String GPU_URI = "yarn.io/gpu";
public static final String FPGA_URI = "yarn.io/fpga";
已经定义的资源是上面四大类,其他未曾定义的资源,可以自行定义在相应的Resource-type.xml文件中。

3:JobClient

谈到这里,还是有一个概念隐藏在各处,但是并未详述,这就是JobClient。

无论是在HDFS中,还是在Yarn中,都存在着一个Client的概念,或者更进一步地说,我们平时提交的作业,操作的HDFS Shell脚本,并非是真正与ResourceManager或者NameNode打交道,而是与Client打交道,这个Client把我们的命令,真正提交给后端的服务。

就Yarn来说,其中已经有了指定的MRAppMaster,在我们提交MapReduce作业的时候,实际上提交的是MRAppMaster,然后由JobClient提交给了RM,当RM知道有了一个新的作业,会估量资源是否足够,然后首先分配资源,先把ApplicationMaster启动起来,等到MRApplicationMaster启动之后,才是我们本文讨论的后续细节(这里回答了上文的潜藏问题1)。

就本文而言,更偏向于静态的概念描述,文中提到的一些未解决的问题,倾向于动态的运行过程,我们提交的一个作业,究竟是如何在Yarn的资源调度框架下完整运行起来,运行过程中报出的那些异常,到底都是哪些类的问题,解决这些问题,更有助于我们对于Yarn的深刻理解。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值