前言
几年前,我在刚刚进入大数据领域的时候,很快就了解到Hive所提供的一种另类的SQL。最初使用Hive的命令行提交任务,后来便用上了HiveServer和HiveServer2。半年前第一次注意到Spark的Thrift服务,当时心中就笃定它肯定与HiveServer2有着某种联系,直到在工作中真正使用它。
在使用HiveThriftServer2的过程中,通过故障排查、源码分析和功能优化,HiveThriftServer2的实现及其原理就浮上水面。等我了解了HiveThriftServer2,情不自禁的就会和Tomcat进行一番比较,尤其是在组件的生命周期管理方面。有兴趣的同学可以先阅读下我之前写得《Tomcat7.0源码分析——生命周期管理》一文。Tomcat将内部组件都抽象为容器,而HiveThriftServer2的内部组件都是服务。HiveThriftServer2对服务的抽象不是本来固有的,而是继承自HiveServer2的。根据HiveServer2的设计,所有的服务都需要实现Service接口。
本文将从HiveThriftServer2的Service接口设计、生命周期管理、启动过程分析三个角度深入分析。
一切都是服务
早年间火热的SOA技术,有一个关键的修饰语——“一切都是服务”,今天拿来形容HiveThriftServer2及HiveServer2中的组件抽象却恰如其分。HiveServer2定义了Service接口,其中包含的接口方法见代码清单1。
代码清单1 Service的定义
void init(HiveConf conf);
void start();
void stop();
void register(ServiceStateChangeListener listener);
void unregister(ServiceStateChangeListener listener);
String getName();
HiveConf getHiveConf();
STATE getServiceState();
long getStartTime();
代码清单1展示了Service定义的各个接口方法,它们分别是:
- init:对服务组件进行初始化
- start:启动服务组件
- stop:停止服务组件
- register:注册对服务组件的状态感兴趣的监听器,监听器由ServiceStateChangeListener接口定义。ServiceStateChangeListener只有stateChanged一个方法用来处理服务组件的状态。
- unregister:撤销对服务组件的状态感兴趣的监听器
- getName:获取服务组件的名称
- getHiveConf:获取初始化服务组件时,设置的HiveConf
- getServiceState:获取服务组件的状态。方法返回的枚举类型STATE定义了服务组件所能拥有的所有可能状态,包括:未初始化(NOTINITED)、初始化(INITED)、已启动(STARTED)、已停止(STOPPED)。
- getStartTime:获取服务组件的启动时间。
HiveServer2的抽象类AbstractService中实现了Service的所有接口,AbstractService中有以下属性:
- state:服务组件的初始状态,默认为NOTINITED。
- name:服务组件的名称。
- startTime:服务组件的启动时间。
- hiveConf:服务组件初始化时设置的hiveConf。
- listeners:用于缓存对服务组件的状态感兴趣的所有ServiceStateChangeListener的列表。
有了对这些属性的了解,AbstractService实现的方法如下:
服务初始化
AbstractService实现的初始化方法见代码清单2.
代码清单2
public synchronized void init(HiveConf hiveConf) {
ensureCurrentState(STATE.NOTINITED); //确认服务组件的当前状态是否一致
this.hiveConf = hiveConf;
changeState(STATE.INITED); //将服务组件的状态修改为INITED
LOG.info("Service:" + getName() + " is inited.");
}
changeState方法除了修改服务组件的状态外,还会触发所有监听器,见代码清单3.
代码清单3
private void changeState(STATE newState) {
state = newState;
// notify listeners
for (ServiceStateChangeListener l : listeners) {
l.stateChanged(this);
}
}
服务启动
AbstractService实现的启动方法见代码清单4.
代码清单4
public synchronized void start() {
startTime = System.currentTimeMillis();
ensureCurrentState(STATE.INITED);
changeState(STATE.STARTED); //将服务组件的状态修改为STARTED
LOG.info("Service:" + getName() + " is started.");
}
服务停止
AbstractService实现的启动方法见代码清单5.
代码清单5
public synchronized void stop() {
if (state == STATE.STOPPED ||
state == STATE.INITED ||
state == STATE.NOTINITED) {
// already stopped, or else it was never
// started (eg another service failing canceled startup)
return;
}
ensureCurrentState(STATE.STARTED);
changeState(STATE.STOPPED); //将服务组件的状态修改为STOPPED
LOG.info("Service:" + g