2021SC@SDUSC
Hadoop yarn源码分析(二) NodeManager源码分析
- 一、NM简介
- 二、内部架构
- 三、基本职能
- 3.1 ResourceTrackerProtocol协议
- 3.1.1 注册:registerNodeManager
- 3.1.2 心跳:nodeHeartbeat
- 3.2 ContainerManagementProtocol协议
- 四、NM初始化
一、NM简介
Yarn的三大核心组件为ResourceManager(RM),ApplicationMaster(AM),NodeMananger(NM)。
NodeManager是执行在单个节点上的代理,负责管理Hadoop集群中的单个计算节点。主要有与ResourceManager保持通信,监控管理Container的生命周期和使用情况,管理日志和不同应用程序用到的附属服务等功能。
二、内部架构
1.NodeStatusUpdater:这个组件是NM与RM通信的唯一通道,包括NM注册之后向RM的注册汇报资源,以及周期性的汇报节点信息和Container的运行状态,同时RM会返回给待清理的Container列表,待清理的应用程序,诊断信息等。
2.ContainerManager: 该组件是NM最核心的组件之一,由许多组件构成,各组件共同管理运行在该节点上的所有Container。部分组件的功能如下:
(1)RPCServer :实现了ContainerManagementProtocol协议,是AM和NM通信的唯一通道。
ContainerManager从各个ApplicationMaster上接受RPC请求以启动新的Container或者停止正在执行的Contaier。
(2)ContainerEventDispatcher:Container的事件调度器,负责将ContainerEvent类型的事件调度给对应Container的状态机ContainerImpl。
(3)ApplicationEventDispatcher: Application的事件调度器,负责将ApplicationEvent类型的事件调度给Application的状态机ApplicationImpl。
3.ContainerExecutor: 它可与底层的操作系统交互,安全存放Container的文件和目录,进而安全的启动和清理Container。
4.NodeHealthCheckerService: 周期性运行一个向磁盘写文件的脚本,检测节点的健康状态,并汇报给RM。
5.DeletionService: NodeManager删除文件组件。
6.Security: 安全模块。
7.WebServer: 通过Web界面向用户展示该节点上所有应用程序运行状态、 Container列表、 节点健康状况和Container产生的日志等。
三、基本职能
NM通过两个RPC协议与AM进行交互,从AM上接收Container相关命令(启动、停止Container)并执行,向RM汇报Container的运行状态和节点健康状态,并领取相关Container的命令执行。两个RPC协议分别是ResourceTrackerProtocol协议,ContainerManagementProtocol协议。
3.1 ResourceTrackerProtocol协议
在该协议中,RM相当于RPC Server,NM相当于RPC Client。NM通过该RPC协议向RM注册汇报节点的健康状态以及Container的运行状态,并接收RM命令,如初始化、清理Container等。
协议具体代码:
syntax = "proto2";
option java_package = "org.apache.hadoop.yarn.proto";
option java_outer_classname = "ResourceTracker";
option java_generic_services = true;
option java_generate_equals_and_hash = true;
package hadoop.yarn;
import "yarn_server_common_service_protos.proto";
service ResourceTrackerService {
rpc registerNodeManager(RegisterNodeManagerRequestProto) returns (RegisterNodeManagerResponseProto);
rpc nodeHeartbeat(NodeHeartbeatRequestProto) returns (NodeHeartbeatResponseProto);
rpc unRegisterNodeManager(UnRegisterNodeManagerRequestProto) returns (UnRegisterNodeManagerResponseProto);
}
3.1.1 注册:registerNodeManager
注册,需要将自己的http端口号(httpPort),RPC端口号(nodeId)以及总资源量(totalResource)传送给RM,在RegisterNodeManagerRequest将这些必要信息封装。
RegisterNodeManagerRequest封装:
//org.apache.hadoop.yarn.server.api.protocolrecords.RegisterNodeManagerRequest.java
public static RegisterNodeManagerRequest newInstance(NodeId nodeId,
int httpPort, Resource resource, String nodeManagerVersionId,
List<NMContainerStatus> containerStatuses,
List<ApplicationId> runningApplications) {
return newInstance(nodeId, httpPort, resource, nodeManagerVersionId,
containerStatuses, runningApplications, null);
}
3.1.2 心跳:nodeHeartbeat
NM启动后,通过RPC协议向RM注册。汇报节点健康状况和Container执行状态,并领取新的命令,包含又一次初始化、清理Container资源等。
//org.apache.hadoop.yarn.server.resourcemanager.ResourceTrackerService.java
protected void serviceInit(Configuration conf) throws Exception {
RackResolver.init(conf);
if (YarnConfiguration.areNodeLabelsEnabled(conf)) {
isDistributedNodeLabelsConf =
YarnConfiguration.isDistributedNodeLabelConfiguration(conf);
isDelegatedCentralizedNodeLabelsConf =
YarnConfiguration.isDelegatedCentralizedNodeLabelConfiguration(conf);
}
updateHeartBeatConfiguration(conf);
loadDynamicResourceConfiguration(conf);
decommissioningWatcher.init(conf);
super.serviceInit(conf);
}
3.2 ContainerManagementProtocol协议
应用程序的AM通过RPC协议向NM发起针对Container的相关操作,包含启动Container、杀死Container、获取Container运行状态。AM能将Container的相关信息通过RPC的方式第一时间传送给NM。
主要提供了三个RPC函数:
1.startContainer:有一个參数封装了Container启动所须要的本地资源、环境变量、运行命令、Token等信息。
2.stopContainer:AM通过该RPC要求NodeManager停止(杀死)一个Container。该函数有一个StopContanerRequest类型的參数,用于指定待杀死的Container ID.
3.getContainerStatus:AM通过该RPC获取一个Container的执行状态。该函数參数类型为GetContaineStatusRequest,封装了目标Container 的ID。
四、NM初始化
NodeManager的服务初始化都是由serviceInit方法来处理的,里面详细的描述了NM服务用到的子服务。包含node资源监控服务、容器管理服务、web通讯服务、安全服务等。
//org.apache.hadoop.yarn.server.nodemanager.Nodemanager.java
protected void serviceInit(Configuration conf) throws Exception {
...
//创建创建 ContainerExecutor
ContainerExecutor exec = createContainerExecutor(conf);
try {
//初始化
exec.init(context);
} catch (IOException e) {
throw new YarnRuntimeException("Failed to initialize container executor", e);
}
DeletionService del = createDeletionService(exec);
addService(del);
// NodeManager level dispatcher
this.dispatcher = createNMDispatcher();
//健康检测服务
this.nodeHealthChecker = new NodeHealthCheckerService(dirsHandler);
addService(nodeHealthChecker);
((NMContext)context).setContainerExecutor(exec);
((NMContext)context).setDeletionService(del);
nodeStatusUpdater =
createNodeStatusUpdater(context, dispatcher, nodeHealthChecker);
nodeLabelsProvider = createNodeLabelsProvider(conf);
if (nodeLabelsProvider != null) {
addIfService(nodeLabelsProvider);
nodeStatusUpdater.setNodeLabelsProvider(nodeLabelsProvider);
}
//node属性
nodeAttributesProvider = createNodeAttributesProvider(conf);
if (nodeAttributesProvider != null) {
addIfService(nodeAttributesProvider);
nodeStatusUpdater.setNodeAttributesProvider(nodeAttributesProvider);
}
//node资源监控服务
nodeResourceMonitor = createNodeResourceMonitor();
addService(nodeResourceMonitor);
((NMContext) context).setNodeResourceMonitor(nodeResourceMonitor);
//容器管理服务
containerManager =
createContainerManager(context, exec, del, nodeStatusUpdater,
this.aclsManager, dirsHandler);
addService(containerManager);
((NMContext) context).setContainerManager(containerManager);
this.nmLogAggregationStatusTracker = createNMLogAggregationStatusTracker(
context);
addService(nmLogAggregationStatusTracker);
((NMContext)context).setNMLogAggregationStatusTracker(
this.nmLogAggregationStatusTracker);
//web通讯服务
WebServer webServer = createWebServer(context, containerManager
.getContainersMonitor(), this.aclsManager, dirsHandler);
addService(webServer);
((NMContext) context).setWebServer(webServer);
int maxAllocationsPerAMHeartbeat = conf.getInt(
YarnConfiguration.OPP_CONTAINER_MAX_ALLOCATIONS_PER_AM_HEARTBEAT,
YarnConfiguration.
DEFAULT_OPP_CONTAINER_MAX_ALLOCATIONS_PER_AM_HEARTBEAT);
((NMContext) context).setQueueableContainerAllocator(
new DistributedOpportunisticContainerAllocator(
context.getContainerTokenSecretManager(),
maxAllocationsPerAMHeartbeat));
dispatcher.register(ContainerManagerEventType.class, containerManager);
dispatcher.register(NodeManagerEventType.class, this);
addService(dispatcher);
pauseMonitor = new JvmPauseMonitor();
addService(pauseMonitor);
metrics.getJvmMetrics().setPauseMonitor(pauseMonitor);
DefaultMetricsSystem.initialize("NodeManager");
if (YarnConfiguration.timelineServiceV2Enabled(conf)) {
this.nmCollectorService = createNMCollectorService(context);
addService(nmCollectorService);
}
// StatusUpdater should be added last so that it get started last
// so that we make sure everything is up before registering with RM.
addService(nodeStatusUpdater);
((NMContext) context).setNodeStatusUpdater(nodeStatusUpdater);
nmStore.setNodeStatusUpdater(nodeStatusUpdater);
// 安全服务
try {
doSecureLogin();
} catch (IOException e) {
throw new YarnRuntimeException("Failed NodeManager login", e);
}
registerMXBean();
context.getContainerExecutor().start();
super.serviceInit(conf);
}