HDFS NameNode 高可用實現意義

[root@node01 hadoop]# jps
19425 NameNode
12642 SparkSubmit
23571 NodeManager
13942 JournalNode
14231 DFSZKFailoverController
20042 Jps
25675 YarnSessionClusterEntrypoint
13660 DataNode
13214 QuorumPeerMain


[root@node02 hadoop]# jps
928 NodeManager
8594 DFSZKFailoverController
8355 DataNode
7046 Jps
8454 JournalNode
6283 NameNode
1340 ResourceManager
8189 QuorumPeerMain

複製代碼

歷史背景

在 Hadoop 1.0 時代,NameNode 存在單點問題(SPOF,single point of failure ),一旦掛掉,整個 HDFS 都不能訪問,而依賴它的 MapReduce、Hive、HBase 等都將沒法正常服務。node

解決思路

一個 NameNode 有單點問題,若是再提供一個 NameNode 做爲備份,不是能解決問題?這即是主備模式的思想。繼續這個思路,光有備份的 NameNode 夠嗎?咱們知道 NameNode 上存儲的是 HDFS 上全部的元數據信息,所以最關鍵的問題在於 NameNode 掛了一個,備份的要及時頂上,這就意味着咱們要把全部的元數據都同步到備份節點。好,接下來咱們考慮如何同步呢?每次 HDFS 寫入一個文件,都要同步寫 NameNode 和其備份節點嗎?若是備份節點掛了就會寫失敗?顯然不能這樣,只能是異步來同步元數據。若是 NameNode 恰好宕機卻沒有將元數據異步寫入到備份節點呢?那這部分信息豈不是丟失了?這個問題就天然要引入第三方的存儲了,在 HA 方案中叫作「共享存儲」。每次寫文件時,須要將日誌同步寫入共享存儲,這個步驟成功才能認定寫文件成功。而後備份節點按期從共享存儲同步日誌,以便進行主備切換。算法

架構

  • Active NameNode 和 Standby NameNode:兩臺 NameNode 造成互備,一臺處於 Active 狀態,爲主 NameNode,另一臺處於 Standby 狀態,爲備 NameNode,只有主 NameNode 才能對外提供讀寫服務。
  • 主備切換控制器 ZKFailoverController:ZKFailoverController 做爲獨立的進程運行,對 NameNode 的主備切換進行整體控制。ZKFailoverController 能及時檢測到 NameNode 的健康情況,在主 NameNode 故障時藉助 Zookeeper 實現自動的主備選舉和切換,固然 NameNode 目前也支持不依賴於 Zookeeper 的手動主備切換。
  • Zookeeper 集羣:爲主備切換控制器提供主備選舉支持。
  • 共享存儲系統:共享存儲系統是實現 NameNode 的高可用最爲關鍵的部分,共享存儲系統保存了 NameNode 在運行過程當中所產生的 HDFS 的元數據。Active NameNode 和 Standby NameNode 經過共享存儲系統實現元數據同步。在進行主備切換的時候,新的主 NameNode 在確認元數據徹底同步以後才能繼續對外提供服務。

能夠看出,這裏的核心是共享存儲的實現,這些年有不少的 NameNode 共享存儲方案,好比 Linux HA, VMware FT, shared NAS+NFS, BookKeeper, QJM/Quorum Journal Manager, BackupNode 等等。在關於共享存儲設備的選擇上,由於NFS也會有單點故障問題,目前社區已經把由 Clouderea 公司實現的基於 QJM(Quorum Journal Manager)的方案合併到 HDFS 的 trunk 之中而且做爲默認的共享存儲實現。shell

QJM

基於 QJM 的共享存儲系統主要用於保存 EditLog,並不保存 FSImage 文件。FSImage 文件仍是在 NameNode 的本地磁盤上。QJM 共享存儲的基本思想來自於 Paxos 算法,採用多個稱爲 JournalNode 的節點組成的 JournalNode 集羣來存儲 EditLog。每一個 JournalNode 保存一樣的 EditLog 副本。每次 NameNode 寫 EditLog 的時候,除了向本地磁盤寫入 EditLog 以外,也會並行地向 JournalNode 集羣之中的每個 JournalNode 發送寫請求,只要大多數 (majority) 的 JournalNode 節點返回成功就認爲向 JournalNode 集羣寫入 EditLog 成功。若是有 2N+1 臺 JournalNode,那麼根據大多數的原則,最多能夠容忍有 N 臺 JournalNode 節點掛掉。bash

數據同步機制

  1. Active NameNode 提交 EditLog 到 JournalNode 集羣 Active NameNode 提交 EditLog 到 JournalNode 集羣的過程其實是同步阻塞的,可是並不須要全部的 JournalNode 都調用成功,只要大多數 JournalNode 調用成功就能夠了。不然就認爲提交 EditLog 失敗,NameNode 中止服務退出進程。
  2. Standby NameNode 從 JournalNode 集羣同步 EditLog

雖然 Active NameNode 向 JournalNode 集羣提交 EditLog 是同步的,但 Standby NameNode 採用的是定時從 JournalNode 集羣上同步 EditLog 的方式,那麼 Standby NameNode 內存中文件系統鏡像有很大的多是落後於 Active NameNode 的,因此 Standby NameNode 在轉換爲 Active NameNode 的時候須要把落後的 EditLog 補上來。網絡

腦裂問題

假設 NameNode1 當前爲 Active 狀態,NameNode2 當前爲 Standby 狀態。若是某一時刻 NameNode1 對應的 ZKFailoverController 進程發生了「假死」現象,那麼 Zookeeper 服務端會認爲 NameNode1 掛掉了,根據前面的主備切換邏輯,NameNode2 會替代 NameNode1 進入 Active 狀態。可是此時 NameNode1 可能仍然處於 Active 狀態正常運行,即便隨後 NameNode1 對應的 ZKFailoverController 由於負載降低或者 Full GC 結束而恢復了正常,感知到本身和 Zookeeper 的 Session 已經關閉,可是因爲網絡的延遲以及 CPU 線程調度的不肯定性,仍然有可能會在接下來的一段時間窗口內 NameNode1 認爲本身仍是處於 Active 狀態。這樣 NameNode1 和 NameNode2 都處於 Active 狀態,均可以對外提供服務。架構

這種狀況對於 NameNode 這類對數據一致性要求很是高的系統來講是災難性的,數據會發生錯亂且沒法恢復。Zookeeper 社區對這種問題的解決方法叫作 fencing,中文翻譯爲隔離,也就是想辦法把舊的 Active NameNode 隔離起來,使它不能正常對外提供服務。ssh

在進行 fencing 的時候,會執行如下的操做:異步

首先嚐試調用這個舊 Active NameNode 的 HAServiceProtocol RPC 接口的 transitionToStandby 方法,看能不能把它轉換爲 Standby 狀態。 若是 transitionToStandby 方法調用失敗,那麼就執行 Hadoop 配置文件之中預約義的隔離措施,Hadoop 目前主要提供兩種隔離措施,一般會選擇 sshfence: sshfence:經過 SSH 登陸到目標機器上,執行命令 fuser 將對應的進程殺死; shellfence:執行一個用戶自定義的 shell 腳原本將對應的進程隔離;oop

參考文章 zhuanlan.zhihu.com/p/66245906spa

相關文章
相關標籤/搜索