HDFS-HA:Hadoop-Cloudera-cdh4版本的HDFS自动Failover(zk-based-failover)分析
阅读原文时间:2021年04月20日阅读:3

转帖请注明本空间地址:http://blog.csdn.net/chenpingbupt

从evernote粘过来的格式还是乱了,文末附上格式良好的原文截图

本文基于cloudera-Hadoop-cdh-4.01版本进行分析

在这个特定版本支持HA的Hadoop内,FailoverController主要是通过一个独立于NN的进程来完成的,在这个版本内是通过zookeeper的功能来完成的,所以这个版本内的FailoverController也称为ZKFC。这部分代码主要存在于org.apache.hadoop.ha以及org.apache.hadoop.ha.protocolPB目录下。

在启动NN之前需要先将首先需要将zkfc启动后,如果是第一次启动还需要进行将zkfc进行初始化,初始化的目的主要是在zookeeper中创建必须的监控节点。

ZKFC的格式化方式为:sh bin/hdfs zkfc -formatZK和sh bin/hdfs start zkfc

以下对zkfc的工作流程进行详细分析:

  • 执行zkfc的format或者start的时候,实际是使用org.apache.hadoop.hdfs.tools.DFSZKFailoverController来发起相应的操作,具体执行的是:

  • * 在ToolRunner.run()->tool.setConf(conf)内,首先读取conf文件,从 dfs.ha.namenode.id,dfs.nameservices或dfs.nameservice.id或自动的获取nnid和nsid。获取之后,将各个conf配置减去nsid和nnid这两个后缀重新set的老版本的配置项中。initializeGenericKeys和setGenericConf即完成这个事情。

    • 基于指定的NN建立一个新的conf,基于这些配置项来建立到指定NN的各种网络参数,即:HAServiceTarget。
    • 正式进入ZKFailoverController.doRun(),内面操作如下:
    • * 首先依据配置zk的配置参数进行initZK(),在initZK()内主要完成对ActiveStandbyElector的构造,在构造函数内完成对zk的连接。并且对zk的event注册了WatcherWithClientRef,各个event的响应通过由WatcherWithClientRef.process->ActiveStandbyElector.this.processWatchEvent->ActiveStandbyElectorCallback.xxxx()。ActiveStandbyElector主要是完成选举操作,而与elector进行协调则是通过强制应用实现ActiveStandbyElectorCallback来进行的。ActiveStandbyElectorCallback提供六个操作,如下:
      • * becomeActive()
        • * HAServiceProtocolHelper.transitionToActive -> HAServiceProtocol.transitionToActive(reqInfo) -> NameNodeRpcServer.transitionToActive(StateChangeRequestInfo req) -> nn.transitionToActive() -> state.setState(haContext, ACTIVE_STATE);
        • becomeStandby()
        • * ZKFailoverController.this.becomeStandby() -> localTarget.getProxy(conf, timeout).transitionToStandby(createReqInfo()) ->  NameNodeRpcServer.transitionToStandby(StateChangeRequestInfo req) -> nn.transitionToStandby() ->  state.setState(haContext, STANDBY_STATE);
        • enterNeutralMode()
        • * //not implements yet
        • fenceOldActive(byte[])
        • * ZKFailoverController.this.fenceOldActive(data); -> doFence(target); ->  target.getFencer().fence(target) -> method.method.tryFence(fromSvc, method.arg)
        • notifyFatalError(String)
        • * notifyAll()
      • 如果是参数是-formatZK,那么判断是否在zk已经有对应的lock节点(由参数ha.zookeeper.parent-znode来定义节点名),如有则看是否需要强制format,否则返回。如果没有的话,就建立该lock节点。然后返回。
      • 否则对fencing机制的配置项进行检查。
      • initRPC,依据之前的配置项,借助ProtoBuf为ZKFCProtocolPB提供网络服务,主要提供两个操作:cedeActive和gracefulFailover。其中gracefulFailover主要是提供给HAAdmin提供命令行操作的,而cedeActive则作为doGracefulFailover的过程中的一个步骤来让老的ActiveNN来退位让贤。
      • initHM,构造MonitorDaemon这个daemon线程,在这个线程的run方法内首先基于HAServiceProtocol建立到HAServiceTarget的Rpc连接,值得注意的是:由于zkfc先于NN而启动,所以zkfc会一直连不上NN而阻塞在loopUntilConnected()。连接到NN以后,zkfc会定期通过该rpc调用proxy.monitorHealth()来监测NN的健康状况。依据不同的健康状况调用不同callback进行处理
      • startRPC,启动本地的ZKFCRpcServer,与其他的zkfc进程进行交互。
  • 执行bin/hdfs haadmin  -DFSHAadmin -transitionToActive/Standby nn1时,将会把ActiveNN设置为nn1,具体的过程如下:

  • * DFSHAAdmin首先从conf文件中解析出nn1这个NamespaceID所指代的HAServiceTarget

    • 检查参数中是否带有force,如果是不带force且设置了automatic-Failover,那么将不会进行后续操作,否则继续执行。

    • 从rpc框架中获取到达HAServiceTarget大proxy,然后从在这个proxy上调用rpcProxy.transitionToActive( NULL_CONTROLLER , req)/rpcProxy.transitionToStandby(reqInfo);

    • 目标NN接受该请求以后,再次检查这个请求的来源,合理性。以及执行用户的权限是否足够。

    • 依据当前状态和请求状态,分两种情况处理:

    • Standby->Active首先准备从当前的standby状态中退出,执行的是namesystem.prepareToStopStandbyServices()->standbyCheckpointer .cancelAndPreventCheckpoints(), 这里主要是取消当前的正在进行的Checkpoint以及取消下一个预定执行的Checkpoint

    • 然后执行准备进入Active状态,prepareToEnterState(),目前该操作未实现

    • 接着执行退出Standby状态,context.stopStandbyServices()->namesystem .stopStandbyServices(),在这里会停止CheckpointerThread和EditLogTailerThread,关闭editLog。

    • 在关闭Editlog的时候,如果当前状态是IN_SEGMENT首先会waitForSyncToFinish();然后endCurrentLogSegment( true ),最后journalSet .close()。

    • 设置context的state,即:context.setState(s);

    • 真正的进入Active状态,即:s.enterState(context),其实这里面就是启动ActiveService和TrashEmptier。Active->Standby过程大致相同

    • 首先准备退出执行prepareToExitState,这个方法没有实际操作需要执行

    • 然后准备进入执行prepareToEnterState(context),这个方法没有实际操作需要执行

    • 退出Active状态,执行的是context.stopActiveServices(),这里主要完成stopTrashEmptier();,stopSecretManager(),leaseManager.stopMonitor(),dir.fsImage.editLog.close()以及dir.fsImage.updateLastAppliedTxIdFromWritten();设置context的state,即:context.setState(s);

    • 真正进入Standby状态,执行context.startStandbyServices();主要完成的是dir.fsImage.editLog.initSharedJournalsForRead();editLogTailer .start();standbyCheckpointer .start();这几个线程的初始化。可以看到这几个过程不会判断当前NN的状态是否具备转换为ActiveNN的能力,如当前NN是否与老的ActiveNN的状态是否一致,等等。所以这个操作需要操作人在非常清楚目前各个NN的状态下进行方保无虞。

  • 执行bin/hdfs haadmin  -DFSHAadmin  -failover [--forcefence] [--forceactive] 的时候,会进行一次完整的Failover过程,具体如下:

  • 同理,首先解析fromNN和toNN这两个NamespaceID所指代的HAServiceTarget

  • 判断当前是否这atuomaticHA,如果设置了,判断两个-force参数是否设置,如设置其中之一,便退出,因为HA已经包含这两者。否则继续执行

  • 接下来的操作依据是否设置AutomaticHA,分两种情况进行:

  • 1、设置了AutomaticHA,通过与toNode本地的ZKFC来协商进行一次Failover,具体如下:

  • 1、执行HAAdmin.gracefulFailoverThroughZKFCs (toNode)

  • 2、获取toNode的zkfcProxy,在该Proxy上调用proxy.gracefulFailover();

  • 3、ZKFC-Server接受到该rpc请求之后,首先判断该操作的acl是否容许,如果容许,则继续进行操作。

  • 4、检查本地NN的状态是否healthy,否则异常抛出。

  • 5、检查老的ActiveNN是否即为本地NN,如果是,直接返回。

  • 6、通知老的ActiveNN退出Active状态,即执行oldZkfc.cedeActive(timeout)->zkfc.cedeActive (millisToCede),这个过程需要在进一步分析一下:

  • 1、zkfc接到rpc请求之后,首先判断ack权限是否足够

  • 2、检查recheckElectability,看是否需要设定elector在一个时间段之后再次执行recheckElectability,或是立即joinElection/quitElection。

  • 3、通知本地nn转移到Standby,执行rpcProxy.transitionToStandby (createReqInfo())。如果执行异常了,那么就需要fence了,影响到后续quitElection(needFence)。4、通知elector退出选举,执行elector.quitElection(needFence)->(如果需要fence则执行)tryDeleteOwnBreadCrumbNode->zkClient.close();

  • 5、再次执行recheckElectability()确定何时应该再次参与选举。

  • 7、等待本地的NN被正常的选举为ActiveNN,执行waitForActiveAttempt(timeout + 60000);这个过程通过ActiveStandbyElector的CallBack来完成,在CallBack被通知能够进行becomeActive()的时候,也调用NN.becomeActive()来进行状态转化。

  • 2、在没有设置AutomaticHA的时候,首先初始化一个FailoverController fc = new FailoverController(getConf(), requestSource),然后用这个fc来完成Failover,即:fc.failover(fromNode, toNode, forceFence, forceActive);

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器