问题

对于大型集群来说,ResourceManager 和 NameNode 是整个集群的瓶颈。集群规模越大,RM和NM的压力也就越大。如果这两个组件出了问题,会直接影响到集群的处理能力和吞吐量。

最近在我们的处理集群上,经常发生如下问题:

1. 集群有很多剩余资源,但作业就是获取不到

2. 随着大量的作业提交,RM 上的Pending 作业越来越多性能越来越差,导致很多业务延迟完成

业务部门的人常常抱怨:

怎么才这点任务,集群跑这么慢

昨天跑数据很快,今天怎么这么久还没出结果

我这队列里还有这么多资源,集群还有很多剩余资源的情况下,为什么我的作业一直pending 。

 

分析

从监控数据上我和团队的其他成员发现当运行的App + Pending的App达到一定个数之后,RM的性能会急剧下降。甚至有2倍性能的丢失。

ResourceManager是一个典型的生产者消者模型,所以我们从这个点出发寻找究竟是生产者慢还是消费者慢。对于YARN模型来说,其中的生产者是被动触发的,每次Node过来心跳会触发FairScheduler调度器的nodeUpdate 方法,在这个方法中会给这个Node 分配Container,  并暂存起来,等待被领取。 消费者是每一个AppMaster。 AppMaster 会通过心跳的方式领取分配好的Container。生产者和消费者在这个过程中是异步进行的。其过程如下:

1

图:AppMaster 启动之后的,资源分配流程

 

上图是AppMaster启动之后请求资源过程。生产者是蓝色线条,黄色线条是消费者。

生产者流程:

1. NodeManager 定时通过心跳的方式向ResourceTrackerService汇报当前节点的资源使用情况、Container 状态还有App列表

2. ResourceTrackerService 收到节点心跳之后,会触发FairScheduler类的NODE_UPDATE事件

3. FairScheduler 收到事件后会根据相关策略(FAIR、FIFO、DRF)选择一个队列、选择一个APP、选择一个TASK ,赋给这个节点。同时将分配信息存储在RMAppAttemptImpl中,等待AppMaster来领取。

消费者流程:

4. AppMaster 启动之后会与ResourceManager 的ApplicationMasterService组件通讯,请求资源。

5. ApplicationMasterService收到请求之后会从RMAppAttemptImpl中拿到已经分配好的资源,并返回给AppMaster

在上述过程中会有频繁的线程同步锁互斥锁,另外有很多需要排序地方。

对于目前这种模式来说,一次一跳就会排序多次。

如果Running App + Pending App 过多的话,就会越来越慢。从而导致RM很忙但资源分不出去的问题。

优化

思路:

方案A. 优化代码结构,降低代码中的读写锁时间,同时优化内部队列排序算法(选择队列,选择APP)

方案B. 提升Container分配速度,从一次心跳一次分配变成持续分配(Apache官方解决方案YARN-1010)

 

总结

目前我们使用Apache官方解决方案已经解决这个问题.

官方的Patch 我们用时也出现了一些问题,后来我们修改源码之后基本稳定。

对于调度器的调优可能还有其他方案,我们选择了一个最保守的。后续我们会考虑采用二级调度的方式去解决这个问题。