您的位置:首页 > 大数据 > 人工智能

HDFS-HA:Hadoop-Cloudera-cdh4版本的HDFS自动Failover(zk-based-failover)分析

2012-08-29 21:52 537 查看

转帖请注明本空间地址: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] <serviceId> <serviceId>的时候,会进行一次完整的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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: