HDFS ZKFC自动切换原理分析
2016-11-13 16:54
295 查看
前言
Hadoop社区在HDFS-1623(High Availability Framework for HDFS NN)以及相关JIRA中对NameNode增加了高可用性的支持。但是它的实现需要依赖管理员手动切换NameNode,以此来触发NameNode的切换。这种操作方式有时会带来一些问题,比如说一个NameNode因为非主观原因导致异常,挂了,这个时候怎么办,这个时候我们可能更需要自动切换的一套机制来解决这个问题。毕竟集群管理员不会随时随地地监控着集群。基于这个应用场景,社区在HDFS-3042(Automatic failover support for NN HA)对现有HA的功能增加自动切换的支持。因为HDFS-3042是一个父JIRA,本文我们将主要关注其最后的核心子JIRA,HDFS-2185(HA: HDFS portion of ZK-based FailoverController),也就是基于ZK的自动切换原理实现,对应呈现的形式就是我们平常看到的ZKFC进程。基于ZK的HA切换原理
在讲解ZKFC进程的组成部分之前,我们需要了解HDFS如何依赖ZK实现切换操作的。首先我们需要了解一下什么是ZK以及ZK有什么作用,然后我们才能理解HDFS为什么要利用ZK来实现自动切换的机制。ZK全称是Zookeeper,ZK的一个很大的特点是它可以保持高度的一致性,而且它本身可以支持HA,在ZK集群最后,只要保证半数以上节点存活,ZK集群就还能对外提供服务。
那么HDFS的Active、Standby节点与ZK有什么关联呢?
当一个NameNode被成功切换为Active状态时,它会在ZK内部创建一个临时的znode,在znode中将会保留当前Active NameNode的一些信息,比如主机名等等。当Active NameNode出现失败或连接超时的情况下,监控程序会将ZK上对应的临时znode进行删除,znode的删除事件会主动触发到下一次的Active NamNode的选择。
因为ZK是具有高度一致性的,它能保证当前最多只能有一个节点能够成功创建znode,成为当前的Active Name。这也就是为什么社区会利用ZK来做HDFS HA的自动切换的原因。
HDFS HA自动切换机制的核心:ZKFC
正如本节小标图所显示的,HDFS HA自动切换机制的核心对象是ZKFC ,也就是我们平常在NameNode节点上会启动的ZKFC进程。在ZKFC的进程内部,运行着3个对象服务:
HealthMonitor:监控NameNode是否不可用或是进入了一个不健康的状态。
ActiveStandbyElector:控制和监控ZK上的节点的状态。
ZKFailoverController:协调HealMonitor和ActiveStandbyElector对象,处理它们发来的event变化事件,完成自动切换的过程。
以上3者的运行结果图如图1-1所示。
图 1-1 ZKFC组成以及运行图
接下来我们来简单介绍这3个对象服务。
HealthMonitor
首先是HealthMonitor监控服务,通过它的名称我们就能够看出它是一个监控服务。在此对象内部,定义了5种服务状态,如下代码所示:public enum State { // 1.The health monitor is still starting up. INITIALIZING, // 2.The service is not responding to health check RPCs. SERVICE_NOT_RESPONDING, // 3.The service is connected and healthy. SERVICE_HEALTHY, // 4.The service is running but unhealthy. SERVICE_UNHEALTHY, // 5.The health monitor itself failed unrecoverably and can // no longer provide accurate information. HEALTH_MONITOR_FAILED; }
翻译过来就是下面5种状态:
1.HealMonitor初始化启动状态。
2.健康检查无响应状态。
3.服务检测健康状态。
4.服务检查不健康状态。
5.监控服务本身失败不可用状态。
上述状态最后除去1和5的特殊情况,2、3和4的情况是HealMonitor服务队NameNode的正常检测状况。HealMonitor对象检测NameNode的健康状况的逻辑其实非常简单:发送一个RPC请求,查看是否有响应。相关代码如下:
private class MonitorDaemon extends Daemon { private MonitorDaemon() { super(); ... } @Override public void run() { // 循环监控操作 while (shouldRun) { try { // 尝试连接,直到连接上为止 loopUntilConnected(); // 做一次监控检测的动作 doHealthChecks(); } catch (InterruptedException ie) { Preconditions.checkState(!shouldRun, "Interrupted but still supposed to run"); } } } }
这里继续进入doHealthChecks方法,
private void doHealthChecks() throws InterruptedException { while (shouldRun) { HAServiceStatus status = null; boolean healthy = false; try { status = proxy.getServiceStatus(); // 调用一次监控对象的RPC方法 proxy.monitorHealth(); healthy = true; } catch (Throwable t) { // 如果出现异常情况 if (isHealthCheckFailedException(t)) { ... // 进入服务不健康状态 enterState(State.SERVICE_UNHEALTHY); } else { ... // 进入服务无响应状态 enterState(State.SERVICE_NOT_RESPONDING); Thread.sleep(sleepAfterDisconnectMillis); return; } } ... // 如果都正常,则是服务健康状态 if (healthy) { enterState(State.SERVICE_HEALTHY); } // 进行检测间隔时间的睡眠 Thread.sleep(checkIntervalMillis); } }
在这里我们检测出不同状态之后,会调用enterState方法,在这个方法内部会触发相应状态的回调事件。这些事件会在ZKFailoverController类中被处理。
ActiveStandbyElector
接下来是ActiveStandbyElector对象,ActiveStandbyElector对象主要负责的是与Zookeeper之间的交互操作。比如一个节点成功被切换为Active Name,ActiveStandbyElector对象会在ZK上创建一个节点。在这个类最后,有2个涉及到Active Name选举的关键方法:joinElection()和quitElection()方法。joinElection方法被调用表明本地的NameNode准备参与Active NameNode的选举,为一个备选节点。quitElection方法被调用表示的是本地节点退出本次的选举。
这2个方法会在HDFS HA自动切换最后被调用。显然quitElection方法会在原Active NameNode所在节点中被调用。
在joinElection参加选举的方法中,会执行在ZK上创建临时znode的方法,代码如下:
private void joinElectionInternal() { ... createRetryCount = 0; wantToBeInElection = true; createLockNodeAsync(); }
creareLockNodeAsync方法如下:
private void createLockNodeAsync() { // 调用zk客户端方法创建临时znode zkClient.create(zkLockFilePath, appData, zkAcl, CreateMode.EPHEMERAL, this, zkClient); }
在quitElection退出选举之后,这个临时节点会被删除,相关代码如下:
public synchronized void quitElection(boolean needFence) { LOG.info("Yielding from election"); if (!needFence && state == State.ACTIVE) { // 如果当前NameNode从Active状态变为Standby状态,则删除临时znode tryDeleteOwnBreadCrumbNode(); } reset(); wantToBeInElection = false; }
当然,在ActiveStandbyElector类中还有其它涉及ZK操作的方法,大家可以自行阅读此对象进行更加深入地学习。
ZKFailoverController
最后是ZKFailoverController控制器类,这个对象类包含并协调以上2个对象类的操作。首先来看此对象类的定义,代码如下:public abstract class ZKFailoverController { ... // 服务目标对象 protected final HAServiceTarget localTarget; // NameNode健康监控服务 private HealthMonitor healthMonitor; // ZK交互协调器 private ActiveStandbyElector elector; protected ZKFCRpcServer rpcServer; ...
然后我们再来看HealthMonitor 、ActiveStandbyElector 的初始化。
首先是HealthMonitor 对象,
private void initHM() { // HealthMonitor对象的初始化 healthMonitor = new HealthMonitor(conf, localTarget); // 加入回调操作对象,以此不同的状态变化可以触发这些回调的执行 healthMonitor.addCallback(new HealthCallbacks()); healthMonitor.addServiceStateCallback(new ServiceStateCallBacks()); healthMonitor.start(); }
在之前分析的HealthMonitor类中的enterState方法中会触发这些回调的执行,我们以ServiceStateCallBacks回调为例,来看看里面具体会执行哪些操作。
class ServiceStateCallBacks implements HealthMonitor.ServiceStateCallback { @Override public void reportServiceStatus(HAServiceStatus status) { // 传入当前检测出的健康状态进行检查 verifyChangedServiceState(status.getState()); } }
继续进入此方法,
void verifyChangedServiceState(HAServiceState changedState) { synchronized (elector) { synchronized (this) { // 如果服务状态为初始化状态 if (serviceState == HAServiceState.INITIALIZING) { if (quitElectionOnBadState) { LOG.debug("rechecking for electability from bad state"); recheckElectability(); } // 重新检测方法完毕并返回 return; } ... // 因为当前报告的状态与期望状态不匹配,退出选举 LOG.error("Local service " + localTarget + " has changed the serviceState to " + changedState + ". Expected was " + serviceState + ". Quitting election marking fencing necessary."); delayJoiningUntilNanotime = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(1000); elector.quitElection(true); quitElectionOnBadState = true; ... } } }
在recheckElectability方法中,会根据最近一次检测出的健康状态,做对应的处理动作,代码如下:
private void recheckElectability() { // Maintain lock ordering of elector -> ZKFC synchronized (elector) { synchronized (this) { boolean healthy = lastHealthState == State.SERVICE_HEALTHY; ... // 根据最近一次的健康状态,调用ActiveStandbyElector的相关方法 switch (lastHealthState) { case SERVICE_HEALTHY: // 如果当前状态为健康,则加入此轮选举 elector.joinElection(targetToData(localTarget)); if (quitElectionOnBadState) { quitElectionOnBadState = false; } break; case INITIALIZING: LOG.info("Ensuring that " + localTarget + " does not " + "participate in active master election"); // 如果当前处于初始化状态,则暂时不加入选举 elector.quitElection(false); serviceState = HAServiceState.INITIALIZING; break; case SERVICE_UNHEALTHY: case SERVICE_NOT_RESPONDING: // 如果当前状态为不健康或无响应状态,则退出选择 LOG.info("Quitting master election for " + localTarget + " and marking that fencing is necessary"); elector.quitElection(true); serviceState = HAServiceState.INITIALIZING; break; case HEALTH_MONITOR_FAILED: fatalError("Health monitor failed!"); break; default: throw new IllegalArgumentException("Unhandled state:" + lastHealthState); } } } }
在上面的操作中,就调用到了ActiveStandbyElector的内部方法。在这里我们可以看到,当当前NameNode的健康检测状态为SERVICE_UNHEALTHY和SERVICE_NOT_RESPONDING时,会触发到quitElection方法,从而使自身暂时退出Active状态。
说了这么多关于ZKFailoverController的内容,可能有人会感觉奇怪,我们启动的ZKFC进程好像并不叫这个名称啊?没错,在NameNode,我们实际启动的是它的一个继承子类:DFSZKFailoverController。此类的绝大多数方法走的还是其父类的方法。
综上所述,ZKFC类对象内部的结构关系图如图1-2所示。
图 1-2 ZKFC内部结构图
OK,本文所要阐述的内容就是如此,更多关于HDFS ZKFC自动切换原理的细节内容可以点击文章末尾的链接进行学习。
参考资料
[1].High Availability Framework for HDFS NN[2].Automatic failover support for NN HA
[3].HA: HDFS portion of ZK-based FailoverController
[4].zkfc-design
相关文章推荐
- HDFS集群搭建,高可用双机热备模式(HA)自动切换,hdfs+zookeeper+journalnode,步骤分步原理详解(适合初学者)
- Oracle - PGA自动管理原理深入分析及性能调整(6)
- Oracle - PGA自动管理原理深入分析及性能调整(4)
- HDFS2.X源码分析之:NameNode写文件原理
- second order system analysis 自动控制原理 二阶系统的matlab仿真分析
- HDFS-HA的配置-----自动Failover(ZKFC)
- PGA自动管理原理深入分析及性能调整
- DZ自动爆破工具原理分析
- HDFS原理分析(一)—— 基本概念
- HDFS-HA:Hadoop-Cloudera-cdh4版本的HDFS自动Failover(zk-based-failover)分析
- PGA自动管理原理深入分析
- 基于QJM/Qurom Journal Manager/Paxos的HDFS HA原理及代码分析
- Oracle - PGA自动管理原理深入分析及性能调整(5)
- 对“实现自动切换用户”的一点分析
- 在 JSP/Servlet 中使用 Bean 自动属性填充机制(含原理分析)
- Oracle - PGA自动管理原理深入分析及性能调整(7)
- Oracle - PGA自动管理原理深入分析及性能调整(1)
- 【转】逆向小试 ―― QQ 自动登录器原理分析
- 基于QJM/Qurom Journal Manager/Paxos的HDFS HA原理及代码分析
- SpringMVC关于json、xml自动转换的原理研究[附带源码分析]