「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」
推荐阅读时间:10分钟
字数:1357字
YARN Server工作机制深度剖析
YARN的核心设计理念是服务化(Service) 和事件驱动AsyncDispatcher ( Event + EventHandler/StateMachine) 。服务化和事件驱动软件设计思想的引入,使得YARN具有低耦合、高内聚的特点,各个模块只需完成各自功能,而模块之间则采用事件联系起来,系统设计简单且维护方便。这种编程方式具有异步、并发等特点,更高效,更适合大型分布式系统。
Service在Yarn源码中处处可见,想要阅读源码就得选了解YARN中的Service机制
下面就详细介绍下什么是Service
对于生命周期较长的对象,YARN 采用了基于服务的对象管理模型对其进行管理,该模型主要有以下几个特点。
-
将每个被服务化的对象分为 4 个状态:NOTINITED(被创建)、INITED(已初始化)、STARTED(已启动)、STOPPED(已停止)。
-
任何服务状态变化都可以触发另外一些动作。
-
可通过组合的方式对任意服务进行组合,以便进行统一管理。通俗的解释:一个大 Service 可能会有一堆子 Service
使用场景化驱动的方式来了解YARN Service

我们比较熟悉的ResourceManager其实就是一个Service,它本身就是Service的子类,下面是ResourceManager和NodeManager类的继承类图:
根据类的继承关系,直接看接口Service,接口的具体信息如下:
-
印证了Service都有四个状态:NOTINITED、INITED、STARTED、STOPPED
-
于此同时还有五个重要的方法:构造方法、init()、start()、stop()、close()
public interface Service extends Closeable {
public enum STATE {
NOTINITED(0, "NOTINITED"),
INITED(1, "INITED"),
STARTED(2, "STARTED"),
STOPPED(3, "STOPPED");
}
// 服务初始化
void init(Configuration config);
// 服务启动
void start();
// 服务停止
void stop();
// 服务关闭
void close() throws IOException;
}
复制代码
这四个状态和五个重要的方法之间有不可分割的关系:
了解了Service的主要信息之后,下面从上往下查看各类的具体信息
对于AbstractService类,它实现了结构Service,那么它一定会对上述的四个方法进行实现
public abstract class AbstractService implements Service {
private final String name;
private final ServiceStateModel stateModel;
@Override public void init(Configuration conf) { serviceInit(config); }
@Override public void start() { serviceStart(); }
@Override public void stop() { serviceStop(); }
// 都是空实现!
protected void serviceInit() throws Exception {}
protected void serviceStart() throws Exception { }
protected void serviceStop() throws Exception { }
}
复制代码
通过源码可以看到,虽然对四个方法都已经进行了实现但是都是空实现,这是为什么呢?
使用一个中间类去对父类的方法进行空实现,然后真正的子类去继承中间类,这样可以避免子类去实现父类的一些不必要的方法,此处AbstractService就是中间类,这样的代码设计模式是可以借鉴的
既然AbstractService对这四个方法没有进行实现,下面就来看它的子类CompositeService,来看CompositeService类的具体定义:
- 一个ArrayList,它是一个Service类型的集合,印证了上面的特点:一个大 Service 可能会有一堆子 Service
此处是ArrayList说明Service加入的顺序是保留了下来的,是有顺序的
private final List<Service> serviceList = new ArrayList<Service>();
复制代码
- 从ArrayList中获取Service,上述已经说明列表保留了服务的顺序,由此此处获取Service也是有顺序的
public List<Service> getServices() {
synchronized(serviceList) {
return new ArrayList<Service>(serviceList);
}
}
复制代码
- 添加子 service 的方法
protected void addService(Service service) {
synchronized(serviceList) {
serviceList.add(service);
}
}
protected boolean addIfService(Object object) {
if(object instanceof Service) {
addService((Service) object);
return true;
} else {
return false;
}
}
复制代码
-
针对所有 Service 执行 init 初始化:最终调用 service 的 () 方法
针对所有 Service 执行 start 启动:最终调用 service 的 serviceStart() 方法
protected void serviceInit(Configuration conf) throws Exception {
// 获取当前 service 组件的所有子 service
List<Service> services = getServices();
// 遍历每个 子 service 调用 init() 执行初始化
for(Service service : services) {
service.init(conf);
}
}
protected void serviceStart() throws Exception {
List<Service> services = getServices();
for(Service service : services) {
service.start();
}
}
复制代码
下面看到ResourceManager,它是CompositeService的子类,它实现了方法serviceInit()、serviceStart()、serviceStop()
当ResourceManager进行初始化、开启的时候会调用父类的init、start方法,然后这两个方法再调用本部类重写了的serviceInit()、serviceStart()方法,从而完成具体业务逻辑。
ResourceManager.main(){
// ResourceManager 初始化
Resourcemanager resourceManager = new Resourcemanager();
// 各种服务创建和初始化
resourceManage.init(conf);
//各种服务启动
resourcemanager.start();
}
复制代码
总而言之,在 YARN 中,会有非常非常多的 Service,每个 service 都要初始化和启动,如果Service本身有serviceInit、serviceStart方法,就各自做自己的实现,否则使用父类的实现。
如果阅读 Service 组件的源码,从下面三方面入手:
- 构造方法
- serviceInit() 方法
- serviceStart() 方法
本人在学习的路上,上述文章如有错误还请指教批评。