社區hadoop2.2.0 release版本開始支持NameNode的HA,本文將詳細描述NameNode HA內部的設計與實現。node
原文見 http://xiguada.org/namenode-ha-principle/算法
1.NameNode High Availability即高可用。數據庫
2.NameNode 很重要,掛掉會致使存儲中止服務,沒法進行數據的讀寫,基於此NameNode的計算(MR,Hive等)也沒法完成。apache
1.如何保持主和備NameNode的狀態同步,並讓Standby在Active掛掉後迅速提供服務,namenode啓動比較耗時,包括加載fsimage和editlog(獲取file to block信息),處理全部datanode第一次blockreport(獲取block to datanode信息),保持NN的狀態同步,須要這兩部分信息同步。架構
2.腦裂(split-brain),指在一個高可用(HA)系統中,當聯繫着的兩個節點斷開聯繫時,原本爲一個總體的系統,分裂爲兩個獨立節點,這時兩個節點開始爭搶共享資源,結果會致使系統混亂,數據損壞。app
3.NameNode切換對外透明,主Namenode切換到另一臺機器時,不該該致使正在鏈接的客戶端失敗,主要包括Client,Datanode與NameNode的連接。異步
1.非HA的Namenode架構分佈式
一個HDFS集羣只存在一個NN,DN只向一個NN彙報,NN的editlog存儲在本地目錄。ide
圖1,NN HA架構(從社區複製)svn
社區的NN HA包括兩個NN,主(active)與備(standby),ZKFC,ZK,share editlog。流程:集羣啓動後一個NN處於active狀態,並提供服務,處理客戶端和datanode的請求,並把editlog寫到本地和share editlog(能夠是NFS,QJM等)中。另一個NN處於Standby狀態,它啓動的時候加載fsimage,而後週期性的從share editlog中獲取editlog,保持與active的狀態同步。爲了實現standby在sctive掛掉後迅速提供服務,須要DN同時向兩個NN彙報,使得Stadnby保存block to datanode信息,由於NN啓動中最費時的工做是處理全部datanode的blockreport。爲了實現熱備,增長FailoverController和ZK,FailoverController與ZK通訊,經過ZK選主,FailoverController經過RPC讓NN轉換爲active或standby。
2.關鍵問題:
(1) 保持NN的狀態同步,經過standby週期性獲取editlog,DN同時想standby發送blockreport。
(2) 防止腦裂
共享存儲的fencing,確保只有一個NN能寫成功。使用QJM實現fencing,下文敘述原理。
datanode的fencing。確保只有一個NN能命令DN。HDFS-1972中詳細描述了DN如何實現fencing
(a) 每一個NN改變狀態的時候,向DN發送本身的狀態和一個序列號。
(b) DN在運行過程當中維護此序列號,當failover時,新的NN在返回DN心跳時會返回本身的active狀態和一個更大的序列號。DN接收到這個返回是認爲該NN爲新的active。
(c) 若是這時原來的active(好比GC)恢復,返回給DN的心跳信息包含active狀態和原來的序列號,這時DN就會拒絕這個NN的命令。
(d) 特別須要注意的一點是,上述實現還不夠完善,HDFS-1972中還解決了一些有可能致使誤刪除block的隱患,在failover後,active在DN彙報全部刪除報告前不該該刪除任何block。
客戶端fencing,確保只有一個NN能響應客戶端請求。讓訪問standby nn的客戶端直接失敗。在RPC層封裝了一層,經過FailoverProxyProvider以重試的方式鏈接NN。經過若干次鏈接一個NN失敗後嘗試鏈接新的NN,對客戶端的影響是重試的時候增長必定的延遲。客戶端能夠設置重試此時和時間。
1 FailoverController實現下述幾個功能
(a) 監控NN的健康狀態
(b) 向ZK按期發送心跳,使本身能夠被選舉。
(c) 當本身被ZK選爲主時,active FailoverController經過RPC調用使相應的NN轉換爲active。
2 爲何要做爲一個deamon進程從NN分離出來
(1) 防止由於NN的GC失敗致使心跳受影響。
(2) FailoverController功能的代碼應該和應用的分離,提升的容錯性。
(3) 使得主備選舉成爲可插拔式的插件。
圖2 FailoverController架構(從社區複製)
(1) HealthMonitor 監控NameNode是否處於unavailable或unhealthy狀態。當前經過RPC調用NN相應的方法完成。
(2) ActiveStandbyElector 管理和監控本身在ZK中的狀態。
(3) ZKFailoverController 它訂閱HealthMonitor 和ActiveStandbyElector 的事件,並管理NameNode的狀態。
圖
圖3 QJM架構
(1) 初始化後,Active把editlog日誌寫到2N+1上JN上,每一個editlog有一個編號,每次寫editlog只要其中大多數JN返回成功(即大於等於N+1)即認定寫成功。
(2) Standby按期從JN讀取一批editlog,並應用到內存中的FsImage中。
(3) 如何fencing: NameNode每次寫Editlog都須要傳遞一個編號Epoch給JN,JN會對比Epoch,若是比本身保存的Epoch大或相同,則能夠寫,JN更新本身的Epoch到最新,不然拒絕操做。在切換時,Standby轉換爲Active時,會把Epoch+1,這樣就防止即便以前的NameNode向JN寫日誌,也會失敗。
(4) 寫日誌:
(a) NN經過RPC向N個JN異步寫Editlog,當有N/2+1個寫成功,則本次寫成功。
(b) 寫失敗的JN下次再也不寫,直到調用滾動日誌操做,若此時JN恢復正常,則繼續向其寫日誌。
(c) 每條editlog都有一個編號txid,NN寫日誌要保證txid是連續的,JN在接收寫日誌時,會檢查txid是否與上次連續,不然寫失敗。
(5) 讀日誌:
(a) 按期遍歷全部JN,獲取未消化的editlog,按照txid排序。
(b) 根據txid消化editlog。
(6) 切換時日誌恢復機制
(a) 主從切換時觸發
(b) 準備恢復(prepareRecovery),standby向JN發送RPC請求,獲取txid信息,並對選出最好的JN。
(c) 接受恢復(acceptRecovery),standby向JN發送RPC,JN之間同步Editlog日誌。
(d) Finalized日誌。即關閉當前editlog輸出流時或滾動日誌時的操做。
(e) Standby同步editlog到最新
(7) 如何選取最好的JN
(a) 有Finalized的不用in-progress
(b) 多個Finalized的須要判斷txid是否相等
(c) 沒有Finalized的首先看誰的epoch更大
(d) Epoch同樣則選txid大的。
參考:
1.https://issues.apache.org/jira/secure/attachment/12480489/NameNode%20HA_v2_1.pdf
2.https://issues.apache.org/jira/secure/attachment/12521279/zkfc-design.pdf
3.https://issues.apache.org/jira/secure/attachment/12547598/qjournal-design.pdf
4.https://issues.apache.org/jira/browse/HDFS-1972
5.https://issues.apache.org/jira/secure/attachment/12490290/DualBlockReports.pdf
6.http://svn.apache.org/viewvc/hadoop/common/branches/branch-2.2.0/
7.http://yanbohappy.sinaapp.com/?p=205