今天聊一聊Hadoop HA架构下Namenode的状态转换,也即如下两种转换:
Active -----> Standby
Standby ------> Active
这两种转换分别对应了NameNode类的两个方法:transitionToActive和transitionToStandby
相关的方法在HAServiceProtocol中定义,最终由NameNodeRpcServer的对应方法相应。我们直接从NameNodeRpcServer类中的方法看起
一、transitionToStandby
首先来看由Active -----> Standby
transitionToStandby方法分成三部分:
①检查NN是否已经启动
②检查改变NN状态的请求是否是有效的。例如当配置了auto failover后,HAAdmin Cli的非强制转换NN状态请求会被拒绝;如果是来自ZKFC但是没有配置auto failover也会被拒绝。
③转换成standby NN
所以我们主要关注③中的transitionToStandby()方法。点进去:
这个方法是NameNode类中的一个synchronized方法。首先检查了用户是不是有超级用户的特权,这个我们不用关心。然后判断如果没有启用HA的话,抛出异常。最后也是最重要的是调用了HAState#setState方法把当前的NN状态变成StandBy状态。
state.setState(haContext, STANDBY_STATE);
HAState在HA模式下有两个子类。分别是ActiveState
和StandbyState
,如下图。
因为我们是从Active->StandBy。所以当前是Active的,所以上面调用的setState方法是ActvieState类中的setState方法。追进去看:
追到setStateInternal方法中:
这个方法的主要逻辑是:
①做一些退出当前状态的准备工作
②进入新状态的准备工作
③获取写锁,退出现在的状态,设置新状态,进入新状态,更新最近一次HA状态转换的时间为当前系统时间。释放写锁。
我们对上面的①②③分别介绍:
①做一些退出当前状态的准备工作
通过层层追踪,最终到这个方法,目的是取消StandBy状态节点上正在进行的checkpoint操作。由于我们现在是Active,所以standbyCheckpointer是null,也就是什么都不做。
image.png②进入新状态的准备工作
这个方法在prepareToExitState之后调用,在exitState之前调用。而且需要被子类重写。由于我没有找到有谁重写了这个方法,所以跳过。可能后面的版本会有?
③获取写锁,退出现在的状态,设置新状态,进入新状态,更新最近一次HA状态转换的时间为当前系统时间。释放写锁。
首先是退出当前的状态,这一步会去调用FSNamesystem#stopActiveServices方法来停止一些线程的工作,这个方法是Active,Standby停止服务的通用方法,所以会去判空,比如StandBy节点没有leaseManager等。对于Standby节点则停止editlogRoller等,对于Active节点则停止leasemanager、cacheManager,blockManager等管理类 。重要的一步是更新最后写入Editlog的transaction id。
接着把HAContext的state设置为StandBy。
然后准备进入StandBy状态,即调用StandbyState#enterState。最终调用了FSNamesystem#startStandbyServices方法,如下:
image.png
这个方法主要做了这些工作:把EditLog状态变成可读,设置blockManager能够把一些块汇报放到延迟处理队列中,取消quota,开启一个editLogTailer用来拉取editlog,开启一个standbyCheckpointer。
其实到这里就结束了transitionToStandby。接下来挖个坑,后续研究editLogTailer,standbyCheckpointer这两个组件。
二、transitionToActive
下面来看Standby ------> Active。看过了从Active->StandBy,就很好理解了,过程很相似(反向操作)。
不同之处在于从Standby--->Active状态切换ActiveState#enterState调用的方法是FSNamesystem#stopStandbyServices和FSNamesystem#startActiveServices方法,来关闭当前的standby服务并启动成为Active节点所需要的服务。
首先来看FSNamesystem#stopStandbyServices方法:
主要工作就是把standbyCheckpointer和editLogTailer停止掉,关闭当前的editlog。
接下来看FSNamesystem#startActiveServices方法:
这个方法其实就是和上面的stop对应,把上面关掉的服务启动起来,走进startActiveServices方法看一下:
代码很长,一点一点来分析。
首先检查editlog是不是open for write。 如果editlog处在IN_SEGMENT或者BETWEEN_LOG_SEGMENTS状态,则是open for write的。如果不是就进入到if语句中去。
接着调用FSEditLog#initJournalsForWrite方法,初始化多种JournalManager,并加入到JournalSet中,使FSEditLog状态进入BETWEEN_LOG_SEGMENTS 状态。
接着对editlog进行恢复操作(也就是要finalize editlog),接着要与之前的Active节点的同步editlog内容,把editlog加载到当前的fsimage中。
由于要变成Active,所以不再延时处理数据块,所以调用
blockManager.setPostponeBlocksFromFuture(false);
把所有datanode设置为stale的,直到收到它们的心跳。清除blockManager中所有的队列,处理之前由于Namespace信息不完整而延迟处理的数据块。读取最新的txid,重置editlog的txid,之后打开editlog。
剩下的就是启动一些线程:cacheManager、nnEditLogRoller、NameNode资源监控线程、blockManager线程。
END!
网友评论