NameNode的ZKFC機制


轉自: http://hackershell.cn/?p=821

 

NameNode的HA可以個人認為簡單分為共享editLog機制和ZKFC對NameNode狀態的控制

在此之前,我先提幾個問題:

  • 一般導致NameNode切換的原因

  • ZKFC的作用是什么?如何判斷一個NN是否健康

  • NameNode HA是如何實現的?

  • NameNode因為斷電導致不能切換的原理,怎樣進行恢復

一般導致NameNode切換的原因

隨着集群規模的變大和任務量變多,NameNode的壓力會越來越大,一些默認參數已經不能滿足集群的日常需求,除此之外,異常的Job在短時間內創建和刪除大量文件,引起NN節點頻繁更新內存的數據結構從而導致RPC的處理時間變長,CallQueue里面的RpcCall堆積,甚至嚴重的情況下打滿CallQueue,導致NameNode響應變慢,甚至無響應,ZKFC的HealthMonitor監控自己的NN異常時,則會斷開與ZooKeeper的鏈接,從而釋放鎖,另外一個NN上的ZKFC進行搶鎖進行Standby到Active狀態的切換。這是一般引起的切換的流程。

當然,如果你是手動去切換這也是可以的,當Active主機出現異常時,有時候則需要在必要的時間內進行切換。

ZKFC的作用是什么?如何判斷一個NN是否健康

在正常的情況下,ZKFC的HealthMonitor主要是監控NameNode主機上的磁盤還是否可用(空間),我們都知道,NameNode負責維護集群上的元數據信息,當磁盤不可用的時候,NN就該進行切換了。

 /**
   * Return true if disk space is available on at least one of the configured * redundant volumes, and all of the configured required volumes. * * @return True if the configured amount of disk space is available on at * least one redundant volume and all of the required volumes, false * otherwise. */ public boolean hasAvailableDiskSpace() {  return NameNodeResourcePolicy.areResourcesAvailable(volumes.values(), minimumRedundantVolumes); } 注: minimumRedundantVolumes獲取值的方法如下:
minimumRedundantVolumes = conf.getInt(
        DFSConfigKeys.DFS_NAMENODE_CHECKED_VOLUMES_MINIMUM_KEY,
        DFSConfigKeys.DFS_NAMENODE_CHECKED_VOLUMES_MINIMUM_DEFAULT);

其中,

 

DFS_NAMENODE_CHECKED_VOLUMES_MINIMUM_KEY = "dfs.namenode.resource.checked.volumes.minimum";
DFS_NAMENODE_CHECKED_VOLUMES_MINIMUM_DEFAULT = 1;

 volumes 獲取自 配置項dfs.namenode.shared.edits.dir的值

 

除了可用狀態(SERVICE_HEALTHY)之外,還有SERVICE_UNHEALTHY(磁盤空間不可用),SERVICE_NOT_RESPONDING(其他的一些情況)狀態,在這兩個狀態中,它都認為NN是不健康的。

NameNode HA是如何實現的?

我們前面說到,ZKFC是如何判斷NN是否健康,接下來當NN處於非健康狀態時,NameNode是如何進行切換的呢?

在ZKFailoverController這個類中,實行了兩個重要的Callbacks函數,一個叫ElectorCallbacks,另一個叫HealthCallbacks,顧名思義就是選舉和健康檢查用的回調函數,其中還有兩個重要的組成部分elector(ActiveStandbyElector)healthMonitor(HealthMonitor),總體的就如上圖所示。

ElectorCallbacks:

/** * Callbacks from elector */ class ElectorCallbacks implements ActiveStandbyElectorCallback { @Override public void becomeActive() throws ServiceFailedException { ZKFailoverController.this.becomeActive(); } @Override public void becomeStandby() { ZKFailoverController.this.becomeStandby(); } ... } 

HealthCallbacks:

 /** * Callbacks from HealthMonitor */ class HealthCallbacks implements HealthMonitor.Callback { @Override public void enteredState(HealthMonitor.State newState) { setLastHealthState(newState); recheckElectability(); } } 

對於HealthMonitor來說,在ZKFC進程啟動的時候,就已經將HealthCallbacks注冊進去了,HealthMonitor都會定期的檢查NameNode是否健康,我們可以通過監控ha.health-monitor.check-interval.ms去設置監控的間隔時間和通過參數ha.health-monitor.rpc-timeout.ms設置timeout時間,當集群變大的時候,需要適當的設置改值,讓ZKFC的HealthMonitor沒那么“敏感”

ZKFC通過RPC調用監控NN進程,當出現異常時,則進入不同的處理邏輯,以下是簡化的代碼:

 private void doHealthChecks() throws InterruptedException { while (shouldRun) { try { status = proxy.getServiceStatus(); proxy.monitorHealth(); healthy = true; } catch (HealthCheckFailedException e) { ... enterState(State.SERVICE_UNHEALTHY); } catch (Throwable t) { ... enterState(State.SERVICE_NOT_RESPONDING); Thread.sleep(sleepAfterDisconnectMillis); return; } ... } 

回調函數就是這么起作用啦,那么回調函數做了什么呢?總的來說,如果NN健康(SERVICE_HEALTHY)就加入選舉,如果不健康就退出選舉(SERVICE_UNHEALTHYSERVICE_NOT_RESPONDING

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

說到退出選舉就關系到elector(ActiveStandbyElector)了,true代表如果NN從Actice變為Standby出現異常是要去fence的,這就是為啥NN會掛掉的原因之一

如何退出選舉?就是close zkClient的鏈接,讓ZooKeeper上面的維持的選舉鎖消失

void terminateConnection() { if (zkClient == null) { return; } LOG.debug("Terminating ZK connection for " + this); ZooKeeper tempZk = zkClient; ... try { tempZk.close(); } catch(InterruptedException e) { LOG.warn(e); } ... } 

對於ActiveStandbyElector來說,他有個WatcherWithClientRef類專門用來監聽ZooKeeper上的的znode的事件變化,當事件變化時,就會調用ActiveStandbyElector的processWatchEvent的方法

watcher = new WatcherWithClientRef(); ZooKeeper zk = new ZooKeeper(zkHostPort, zkSessionTimeout, watcher); 

/** * Watcher implementation which keeps a reference around to the * original ZK connection, and passes it back along with any * events. */ private final class WatcherWithClientRef implements Watcher { ... @Override public void process(WatchedEvent event) { hasReceivedEvent.countDown(); try { hasSetZooKeeper.await(zkSessionTimeout, TimeUnit.MILLISECONDS); ActiveStandbyElector.this.processWatchEvent( zk, event); } catch (Throwable t) { fatalError( "Failed to process watcher event " + event + ": " + StringUtils.stringifyException(t)); } } ... } 

在ActiveStandbyElector的processWatchEvent方法中,處理來自不同事件的邏輯重新加入選舉或者繼續監控znode的變化,當另外一個ZKFC監控到事件變化得時候,就去搶鎖,搶鎖實質上就是創建znode的過程,而且創建的是CreateMode.EPHEMERAL類型的,所以,當HealthMonitor監控到NN不健康時,就會斷開連接,節點就會消失,watcher就會監控到NodeDeleted事件,進行創建節點。

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

又因為ActiveStandbyElector實現了StatCallback接口,當節點創建成功時,就會回調processResult方法看是否創建成功,如果創建成功則去檢查zkBreadCrumbPath是否存在之前的Active節點,如果存在,則調用RPC讓其變為Standby,看能否轉變成功,否則則SSH過去fence掉NN進程。,保持Active節點只有一個,並且恢復正常服務

NameNode因為斷電導致不能切換的原理,怎樣進行恢復

ActiveNN斷電,網絡異常,負載過高或者機器出現異常無法連接,Standby NN無法轉化為Active,使得HA集群無法對外服務,原因是Active NN節點在斷電和不能服務的情況下,zknode上保存着ActiveBreadCrumb, ActiveStandbyElectorLock兩個Active NN的信息,ActiveStandbyElectorLock由於Active NN出現異常斷開,Standby NN去搶鎖的時候就會去檢查ActiveBreadCrumb是否有上一次的Active NN節點,如果有,就會就會嘗試讓Active NN變為Standby NN,自己轉化為Active NN,但是由於調用出現異常,所以會采用ssh的方式去Fence之前的Active NN,因為機器始終連接不上,所以無法確保old active NN變為Standby NN,自己也無法變為Active NN,所以還是保持Standby狀態,避免出現腦裂問題。

解決方案是確定Active關機的情況下重新hdfs zkfc -formatZK就可以了。

總 結

NN GC或者在壓力大的情況下可以調整GC算法和增加NameNode節點的線程數,加快NN對請求的處理速度,也可以分離節點的端口dfs.namenode.rpc-address.ns1.nn2dfs.namenode.servicerpc-address.ns1.nn2分離client和datanode節點等服務類型的請求,進行分擔壓力,也可以適當的調整ZKFC的監控timeout的時間等等


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM