怎么实现NodeManager的原理分析
怎么实现NodeManager的原理分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
1、 和其他模块之间的交互接口分析
1)作为client,NodeStatusUpdater通过ResourceTracker协议和RM进行交互。
该API有两个方法
向RM注册NodeManager,参数为httpPort、nodeId、totalResource,其中totalResource为节点的总可分配资源,包括CPU、内存。
向RM心跳,NM启动后通过定期的向RM汇报Container情况,比如处于launched container、已经完成的container、节点的健康信息,并返回领取命令,如kill container。
2)作为服务端,提供ContainerManager服务,通过ContainerManagementProtocol协议为AM提供服务。
该API提供了3个方法
启动containers,参数为StartContainersRequest,也即是StartContainerRequest列表,每个对象是包括启动Container所需要的资源(localResources)、环境变量(environment )、命令(commands)、Token等。
停止containers,参数为StopContainerResult,指定kill的containerId。
获取container状态,参数为GetContainerStatusRequest,指定目标containerId。
2、 几个主要功能类介绍
1)NodeStatusUpdater:周期性的向RM汇报container的状态,包括launched containers、finished containers,返回待clean的Container列表,待clean的Application列表等。
2)ApplicationImpl:NM的应用的状态机宿主对象,管理NM上的该application的所有container;维护一个状态机,记录app的状态之间的迁移和事件,以及事件动作。
3)ContainerImpl:NM的Container的状态机宿主对象,激励container各个状态之间的迁移和事件,以及事件的动作。
4)ContainerManager:提供了RPC服务,启动containers、停止containers、获取container的状态信息;这个类是container管理的启动类。
5)LogHandler:Container的运行日志服务,可以通过参数yarn.nodemanager.log-dirs配置多个日志目录,每个目录的结构是相同的,$log-dir/$appid/$containerid/stderr|stdout|stdlog;有两个实现类,NonAggregationLogHandler、LogAggregationService,由于NM会产生大量的日志,需要进行清理,NonAggregationLogHandler是定期清理日志,LogAggregationService是日志聚集转存的方式上传到HDFS中,默认情况下采用定期清理日志的方式。
6)ResourceLocalizationService:启动container,需要把container需要的Resource本地化,可以根据启动container的参数从hdfs中下载资源,并均匀分布在各磁盘上的数据目录中。本地数据目录,存放执行Container所需要的数据(包括可执行程序、jar、配置等),还有一部分是MR过程中临时产生的中间数据。ResourceLocalizationService启动一个RPC服务(LocalizationProtocol)供下载资源,对于每个container由ContainerLocalizer作为客户端通过LocalizationProtocol协议进行资源下载,并及时heartbeat进行进度报告。
7)ContainersLauncher:维护一个线程池来运行ContainerLaunch任务,该任务生成shelllaunch_container.sh脚本,并随后通过ContainerExecutor.launchContainer启动container进程。
8)ContainerExecutor:启动和清除container的进程。两种实现DefaultContainerExecutor、LinuxContainerExecutor,默认是DefaultContainerExecutor,而LinuxContainerExecutor以更加安全的方式通过Application的拥有者的身份启动和停止Container,并且可以使用Cgroups对CPU资源进行隔离。
9)ContainerMonitor:周期性的探测Container的资源使用量。一旦超过限额,则kill container。内存资源可以通过ContainerMonitor监控,对于CPU还是利用Cgroups。
10)AuxService:随着NM的启动和停止运行的扩展的服务。
11)NodeHealthCheckService:周期性运行自定义脚本和写磁盘文件检查NM的健康,并通过NodeStatusUpdater汇报给RM,一旦不健康则RM不会分配任务给该NM,直到恢复健康。
3、 Container事件流程
1)AM或者RM通过NM的RPC service ContainerManagementProtocol.startContainers启动container
2)NM的服务端ContainerManagerImpl的startContainers逻辑会按照请求的container 数量要求,依次启动container;启动container的逻辑为创建并初始化Application,创建并初始化container。
3)发送事件ApplicationEventType.INIT_APPLICATION到事件处理框架AsyncDispatcher,对于ApplicationEventType类型的事件由ApplicationEventDispatcher进行处理,在该dispatcher handle中调用状态机stateMachine的宿主对象ApplicationImpl的handle方法,该handle方法中调用处理INIT_APPLICATION 事件(状态由ApplicationState.NEW àApplicationState.INITING) 的逻辑AppInitTransition,在该AppInitTransition中发送LogHandlerEventType.APPLICATION_STARTED。
4)LogHandlerEventType.APPLICATION_STARTED由LogAggregationService进行处理,在这里创建Application相关的log目录,后发送ApplicationEventType.APPLICATION_LOG_HANDLING_INITED到事件处理框架。
5)通过AppLogInitDoneTransition对ApplicationEventType.APPLICATION_LOG_HANDLING_INITED进行处理,其中发送LocalizationEventType.INIT_APPLICATION_RESOURCES事件,该事件由ResourceLocalizationService进行处理,其发送ApplicationEventType.APPLICATION_INITED到事件处理框架。
6)由Application中状态机转换逻辑AppInitDoneTransition完成对ApplicationEventType.APPLICATION_INITED事件的处理,并由ApplicationState.INITING, 状态过度到ApplicationState.RUNNING状态;
7)在AppInitDoneTransition逻辑中依次对Application中的container,发送ContainerEventType.INIT_CONTAINER事件,阻塞对该事件的处理一直到container 处于new状态。
8)ContainerEventType.INIT_CONTAINER事件由状态机宿主对象ContainerImpl 中的RequestResourcesTransition逻辑进行处理,进入资源本地化处理,如果有resource需要本地化(下载或者创建),那么就发送INIT_CONTAINER_RESOURCES到ResourceLocalizationService进行处理,并进入到LOCALIZING状态;如果resource都已本地化(已创建或者下载了),那么就发送LAUNCH_CONTAINER事件,并直接进入到LOCALIZED状态。
9)ResourceLocalizationService对INIT_CONTAINER_RESOURCES的处理逻辑是,对container的每一个请求的资源,对应一个LocalResourcesTracker实现,并发送ResourceEventType.REQUEST请求到该tracker中;每种类型的资源都有一个宿主对象LocalizedResource,在tracker中转发该事件给LocalizedResource进行处理,进入状态机的转换(ResourceState.INIT->ResourceState.DOWNLOADING),调用逻辑处理FetchResourceTransition,该transition发送事件LocalizerEventType.REQUEST_RESOURCE_LOCALIZATION,由LocalizerTracker逻辑启用线程LocalizerRunner prepare该container的环境(Application目录、日志目录..),调用ContainerExecutor.startLocalizer启动ContainerLocalizer,并在下载Resource过程中向ResourceLocalizationService汇报进度。
10)Resource资源本地化完成后,首先发送ContainerEventType.RESOURCE_LOCALIZED到ContainerImpl,ContainerImpl随后发送ContainersLauncherEventType.LAUNCH_CONTAINER事件由ContainersLauncher进行处理,将运行container的完整shell写到私有目录下的launch_container.sh中,在处理过程中单独开启线程ContainerLaunch,ContainerLauch生成shelllaunch_container.sh脚本,并启动运行一个container(ContainerExecutor.launchContainer)。
11)运行container,由ContainerExecutor. launchContainer执行shell脚本来完成;shell脚本运行YarnChild MR任务(和MR1一样),运行container过程中一直阻塞直到container运行完成,进入Container资源清理流程
12)Container运行可能成功也可能失败,ContainerImpl收到CONTAINER_EXITED_WITH_SUCCESS事件后,分别向ContainersLauncher和ResourceLocalizationService发送CLEANUP_CONTAINER和CLEANUP_CONTAINER_RESOURCES事件。
13)ContainersLauncher清理Container的临时目录,比如进程PID文件,检查该文件是否存在,若存在则强制回收,回收完成后,ContainerLauncher发送CONTAINER_RESOURCES_CLEANDUP事件到ContainerImpl,后通过向ApplicationImpl、ContainerMonitorImpl、LogHandler发送FINISHED事件,从Container列表中移除该Container,移除对该Container的资源使用量监控。
14) ResourceLocalizationService清理container的相关数据目录(shell脚本等),后向ContainerImpl发送CONTAINER_RESOURCE_CLEANEDUP事件。
注意Container的部分中间数据是在整个应用完成之后清理的,因为只有RM清楚这个Application是否已经完成了。NM NodeStatusUpdater通过ResourceTrackerProtocol协议heartbeat汇报给RM,RM返回需要需要清理的Container列表给NM,NM才彻底清理Container占用的所有资源。
看完上述内容,你们掌握怎么实现NodeManager的原理分析的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!