hdfs-namenode之间自动ha切换过程

整个namenode之间的ha保证是通过ZKFC这个组件来完成的。

  • 该组件核心是以下三个类
    ActiveStandbyElector : 负责跟ZK之间的心跳检查
  • HealthMonitor : 两个namenode之间的心跳检查,主要是看对方的本地磁盘是否足够。若是磁盘空间不足,或者对方响应超时,那么就会触发ha切换
  • ZKFCRpcServer : 接受对方的请求 cedeActive / gracefulFailover 也是比较鸡肋的Server
整个过程是先抢占锁路径 ActiveStandbyElectorLock , 是一个临时路径
再抢占数据路径,是一个永久路径 ActiveBreadCrumb
完整路径是
ha.zookeeper.parent-znode(默认/hadoop-ha) / ActiveStandbyElectorLock  锁路径
ha.zookeeper.parent-znode(默认/hadoop-ha) /ActiveBreadCrumb  数据路径

HealthMonitor :
org.apache.hadoop.ha.HealthMonitor.MonitorDaemon#run 一个while循环的检查doHealthChecks
在doHealthChecks 方法中抛出异常的话,那么进入 enterState(State.SERVICE_NOT_RESPONDING); 这个时候会触发HealthMonitor自身在初始化时候添加的callback=HealthCallbacks .
HealthCallbacks 中通过方法 recheckElectability 检查最后的状态


case SERVICE_NOT_RESPONDING:
LOG.info("Quitting master election for " + localTarget +
" and marking that fencing is necessary");
elector.quitElection(true);
serviceState = HAServiceState.INITIALIZING;
break;

若是SERVICE_NOT_RESPONDING,自己就推出 org.apache.hadoop.ha.ActiveStandbyElector#quitElection 。这个方法主要是断开跟ZK之间的连接

public synchronized void terminateConnection() {
if (zkClient == null) {
return;
}
if (LOG.isDebugEnabled()) {
LOG.debug("Terminating ZK connection for " + this);
}
ZooKeeper tempZk = zkClient;
zkClient = null;
watcher = null;
try {
tempZk.close();
} catch(InterruptedException e) {
LOG.warn(e);
}
zkConnectionState = ConnectionState.TERMINATED;
wantToBeInElection = false;
}

这个时候ActiveStandbyElector要发现作用了。
通过org.apache.hadoop.ha.ActiveStandbyElector.WatcherWithClientRef watch了zk的路径
具体是通过org.apache.hadoop.ha.ActiveStandbyElector#processWatchEvent 中的事件处理

case NodeDeleted:
if (state == State.ACTIVE) {
enterNeutralMode();
}
joinElectionInternal();
break;

检测到路径被删除了,那么就自己去抢路径,在 joinElectionInternal内部的createLockNodeAsync方法中

private void createLockNodeAsync() {
zkClient.create(zkLockFilePath, appData, zkAcl, CreateMode.EPHEMERAL,
this, zkClient);
}

中的第五个参数 this传递进去了,这个this就是ActiveStandbyElector 实现了StatCallback, StringCallback接口,在抢个路径后会触发以下两个方法中的一个

org.apache.hadoop.ha.ActiveStandbyElector#processResult(int, java.lang.String, java.lang.Object, java.lang.String)
org.apache.hadoop.ha.ActiveStandbyElector#processResult(int, java.lang.String, java.lang.Object, org.apache.zookeeper.data.Stat)

进入了 becomeActive

Code code = Code.get(rc);
if (isSuccess(code)) {
// the following owner check completes verification in case the lock znode
// creation was retried
if (stat.getEphemeralOwner() == zkClient.getSessionId()) {
// we own the lock znode. so we are the leader
if (!becomeActive()) {
reJoinElectionAfterFailureToBecomeActive();
}
} else {
// we dont own the lock znode. so we are a standby.
becomeStandby();
}
// the watch set by us will notify about changes
return;
}

完成了最后的namenode ha切换

BTW:如果这段逻辑用 curator-framework来写的话会简单很多。

 

发表评论?

0 条评论。

发表评论


注意 - 你可以用以下 HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>