上一篇介绍了一个job的提交过程。期间多次提到通信协议。那么协议是什么?
协议其实就是通信的双方所遵守的一套规范,这套规范规定了通信时传输的数据的固定的格式。
4.1 RPC协议:在hadoop中,我们采用的是RPC协议。
该协议主要包含四个部分:
序列化层:协议中的参数采用Protocol Buffers来序列化/反序列化。
这个Protocol Buffers是一种数据存储格式,可以理解我们按照其语法格式定义一个数据结构类model,然后使用工具(Protocol Buffers编译器)编译为我们所使用的语言,比如java。接下来,就可以使用对应库提供的Api来操作这个java语言的类来存储我们的数据。
网络传输层:序列化好后就需要传输,采用基于Tcp/IP的Socket机制
服务器端处理框架:传输成功后,就要考虑怎么在Server端进行处理。基于Reactor设计模式的事件驱动I/O模型
函数调用层:这里就是最后一步,怎么调用到具体的函数了。采用了反射和动态代理来实现的。
4.2 Hadoop RPC协议主要组成
4.2.1 server 实现细节(主要负责接到消息后的处理过程)
(1)接收请求
接收RPC 请求,封装为Call类型对象放到一个共享队列(callQueue)中,以便进行后续处理。该阶段内部又分为建立连接和接收请求两个子阶段,分别由Listener 和Reader 两种线程完成。整个Server 只有一个Listener 线程,统一负责监听来自客户端的连接请求,一旦有新的请求到达,它会采用轮询的方式从线程池中选择一个Reader 线程进行处理,而Reader 线程可同时存在多个,它们分别负责接收一部分客户端连接的RPC 请求,至于每个Reader 线程负责哪些客户端连接,完全由Listener 决定,当前Listener 只是采用了简单的轮询分配机制。Listener 和Reader 线程内部各自包含一个Selector 对象,分别用于监听SelectionKey.OP_ACCEPT 和SelectionKey.OP_READ 事件。对于Listener 线程,主循环的实现体是监听是否有新的连接请求到达,并采用轮询策略选择一个Reader 线程处理新连接;对于Reader线程,主循环的实现体是监听(它负责的那部分)客户端连接中是否有新的RPC 请求到达,并将新的RPC 请求封装成Call 对象,放到共享队列callQueue 中。(2)处理请求从共享队列callQueue 中获取Call 对象,执行对应的函数调用,并将结果返回给客户端,这全部由Handler 线程完成。Server 端可同时存在多个Handler 线程,它们并行从共享队列中读取Call 对象,经执行对应的函数调用后,将尝试着直接将结果返回给对应的客户端。但考虑到某些函数调用返回结果很大或者网络速度过慢,可能难以将结果一次性发送到客户端,此时Handler 将尝试着将后续发送任务交给Responder 线程。(3)返回结果前面提到,每个Handler 线程执行完函数调用后,会尝试着将执行结果返回给客户端,但对于特殊情况,比如函数调用返回结果过大或者网络异常情况(网速过慢),会将发送任务交给Responder 线程。Server 端仅存在一个Responder 线程, 它的内部包含一个Selector 对象, 用于监听SelectionKey.OP_WRITE 事件。当Handler 没能将结果一次性发送到客户端时, 会向该Selector 对象注册SelectionKey.OP_WRITE 事件,进而由Responder 线程采用异步方式继续发送未发送完成的结果。4.2.2 client 类(主要负责建立连接发送请求)
Call类和Connection类。
Call类是请求的内容定义以及返回值定义
Connection供客户端建立一个通信连接。各种信息,包括Call类内容,都被封装到Connection中。
4.2.3 RPC类 (对服务器端、客户端的定义和管理)
提供一系列方法供调用,比如构建服务,启动服务等,设置基本参数(比如序列化方式)
4.3 Yarn RPC
将序列化部分剥离出来,自身作为一个工厂,可使用第三方的具体实现,比如Protocol Buffers对应的RPCEngine实现。底层的函数调用机制仍采用Hadoop自带的。
4.4 协议都用在哪?
yarn是资源管理系统负责资源的管理和调度。如果要让应用程序在yarn上得到执行,通常需要编写两个组件:
Client 提交应用程序、查询运行状态
ApplicationMaster 申请资源、与NodeManager通信启动Container,监控各个任务运行状态,失败时重新申请资源。
yarn已为我们实现了。这些组件和yarn框架通信,将使用下一节即将介绍的各种协议。
4.5 主要的RPC协议
我们从一个作业提交、执行、结束整个过程开始捋。
4.6.1 提交 ApplicationClientProtocol
Client和ResourceManager通信。提交、查询Application运行状态活杀死应用程序。
4.6.2 申请资源 ApplicationMastertProtocol
MRAppMaster和ResourceManager通信。注册、申请资源,获取任务运行状态。
4.6.3 执行ContainerManagementProtocol
APPMaster和NodeManager通信。启动/撤销Container活查询Container运行状态。
4.6.4 贯穿全局的ResourceTracker
负责ResourceManager和NodeManager之间的通信。定义了两个主主要的RPC函数:
registerNodeManager 向ResourceManager注册
nodeHearbeat 周期性发送心跳信息
4.6.5 MRAPPMaster
APPMaster启动后,Client和APPMaster直接通信,以减轻ResourceManager负担。