HDFS的高可用性 HDFS的高可用性 利用NAS實現HA QJM高可用

HDFS的高可用性

聯邦hdfs

由於namenode在內存中維護系統中的文件和數據塊的映射信息,所以對於一個海量文件的集羣來說,內存將成爲系統橫向擴展瓶頸。Hadoop在2.x的版本引入了聯邦HDFS(HDFS Federation),通過在集羣中添加namenode實現。

Federation的架構:

原理

1、每個namenode相互獨立,單獨維護一個由namespace元數據和數據塊池(block pool)組成的命名空間卷(namespace volume)——圖中的NS-x。

2、數據塊池包含該命名空間下文件的所有數據塊。命名空間卷相互獨立,兩兩間互不通信,即使一個namenode掛掉,也不會影響其他namenode

3、datanode被用作通用的數據存儲設備,每個datanode要向集羣中所有的namenode註冊,且週期性的向所有namenode發送心跳和報告,並執行來自所有namenode的命令

4、當一個namespace被刪除後,所有datanode上與其對應的block pool也會被刪除。當集羣升級時,每個namespacevolume作爲一個基本單元進行升級。

聯邦hdfs的缺點

雖然引入了多個namenode管理多份namespace,但是對於單個namenode,依然存在單點故障問題(Single point of failure),如果某個namenode掛掉了,那麼所有客戶端都無法操作文件。

聯邦hdfs仍然需要引入secondary namenode。直到secondary namenode滿足以下所有條件時,才能提供服務:

1、將命名空間鏡像導入內存

2、重演編輯日誌

3、接收到足夠的來自datanode的塊映射報告並退出安全模式。

利用NAS實現HA

保障集羣的可用性,可以使用NAS共享存儲。主備namenode之間通過NAS進行元數據同步。但是有一下缺陷:

1、硬件設備必須支持NAS

2、部署複雜,部署完namenode還需要在NFS掛載、解決NFS的單點及腦裂,容易出錯

3、無法實現同一時間只能有一個namenode寫數據

QJM高可用

Hadoop2針對以上問題增加了QJM(Quorum Journal Manager),由多個JN組成,一般配置爲奇數個。QJM中有一對active-standby的namenode。當active namenode失效時,standby namenode會接管它繼續提供服務。

工作原理如下:

1、namenode之間通過一組 journal node 共享編輯日誌,standby namenode接管後,需要讀取整個編輯日誌來與active namenode同步狀態,並繼續讀取active namenode寫入的新操作。

2、datanode需要同時向這組active-standby namenode發送數據塊處理報告,因爲數據塊的映射信息保存在namenode的內存中。

3、客戶端使用ZKFC(zookeeper failover-controller)來處理namenode失效問題,該進程運行在每個namenode上,通過heartbeat監測active namenode是否失效

4、secondary namenode的角色被standby namenode取代,由standby namenode爲active namenode設置check point

5、QJM的實現沒有使用zookeeper。但是在HA選舉active namenode時,使用了zookeeper。

6、在某些特殊情況下(如網速慢),可能發生故障轉移,這時有肯能兩個namenode都是active namenode——腦裂。QJM通過fencing(規避)來避免這種現象。

NameNode 的主備選舉機制

Namenode(包括 YARN ResourceManager) 的主備選舉是通過 ActiveStandbyElector 來完成的,ActiveStandbyElector 主要是利用了 Zookeeper 的寫一致性、 臨時節點和觀察者機制

主備選舉實現如下

1、 創建鎖節點: 如果 ZKFC 檢測到對應的 NameNode 的狀態正常,那麼表示這個 NameNode有資格參加Zookeeper 的主備選舉。如果目前還沒有進行過主備選舉的話,那麼相應的會發起一次主備選舉,嘗試在 Zookeeper 上創建一個路徑爲/hadoopha/${dfs.nameservices}/ActiveStandbyElectorLock 的臨時結點, Zookeeper 的寫一致性會保證最終只會有一次結點創建成功,那麼創建成功的 NameNode 就會成爲主 NameNode, 進而切換爲 Active 狀態。而創建失敗的 NameNode 則切換爲 Standby 狀態。

2、 註冊 Watcher 監聽: 不管創建/hadoop-ha/${dfs.nameservices}/ActiveStandbyElectorLock 節點是否成功, ZKFC 隨後都會向 Zookeeper 註冊一個 Watcher 來監聽這個節點的狀態變化事件, ActiveStandbyElector 主要關注這個節點的 NodeDeleted 事件。

3、 自動觸發主備選舉: 如果 Active NameNode 狀態異常時, ZKFailoverController 會主動刪除臨時結點/hadoop-ha/{dfs.nameservices}/ActiveStandbyElectorLock,這樣處於 Standby 狀態的NameNode 會收到這個結點的 NodeDeleted 事件。收到這個事件之後,會馬上再次進入到建/hadoopha/{dfs.nameservices}/ActiveStandbyElectorLock 結點的流程,如果創建成功,這個本來處於 Standby 狀態的 NameNode 就選舉爲主 NameNode 並隨後開始切換爲 Active 狀態。

4、 當然,如果是 Active 狀態的 NameNode 所在的機器整個宕掉的話,那麼根據 Zookeeper 的臨時節點特性, /hadoop-ha/${dfs.nameservices}/ActiveStandbyElectorLock 節點會自動被刪除,從而也會自動進行一次主備切換。

Namenode 腦裂

腦裂的原因

如果 Zookeeper 客戶端機器負載過高或者正在進行 JVM Full GC,那麼可能會導致 Zookeeper 客戶端到服務端的心跳不能正常發出,一旦這個時間持續較長,超過了配置的 Zookeeper Session Timeout 參數的話, Zookeeper 服務端就會認爲客戶端的 session 已經過期從而將客戶端的 Session 關閉。“假死”有可能引起分佈式系統常說的雙主或腦裂(brain-split) 現象。具體到本文所述的 NameNode,假設 NameNode1 當前爲 Active 狀態,NameNode2 當前爲 Standby 狀態。如果某一時刻 NameNode1 對應的 ZKFC 進程發生了“假死”現象,那麼 Zookeeper 服務端會認爲 NameNode1 掛掉了,根據前面的主備切換邏輯, NameNode2 會替代 NameNode1 進入 Active 狀態。但是此時 NameNode1 可能仍然處於 Active 狀態正常運行,即使隨後 NameNode1 對應的 ZKFailoverController 因爲負載下降或者 Full GC 結束而恢復了正常,感知到自己和 Zookeeper 的 Session 已經關閉,但是由於網絡的延遲以及 CPU 線程調度的不確定性,仍然有可能會在接下來的一段時間窗口內NameNode1 認爲自己還是處於 Active 狀態。這樣 NameNode1 和 NameNode2 都處於Active 狀態,都可以對外提供服務。這種情況對於 NameNode 這類對數據一致性要求非常高的系統來說是災難性的,數據會發生錯亂且無法恢復。

規避腦裂

Hadoop 的 fencing 機制防止腦裂: 中文翻譯爲隔離,也就是想辦法把舊的 Active NameNode

隔離起來,使它不能正常對外提供服務。 ZKFC 爲了實現 fencing,會在成功創建 Zookeeper臨時結點 hadoop-ha/{dfs.nameservices}/ActiveStandbyElectorLock 從而成爲 ActiveNameNode 之後,創建另外一個路徑爲/hadoop-ha/{dfs.nameservices}/ActiveBreadCrumb 的持久節點,這個節點裏面也保存了 Active NameNode 的地址信息。 正常關閉 Active NameNode時, ActiveStandbyElectorLock 臨時結點會自動刪除,同時, ZKFC 會刪除 ActiveBreadCrumb結點。但是如果在異常的狀態下 Zookeeper Session 關閉 (比如前述的 Zookeeper 假死),那麼由於 ActiveBreadCrumb 是持久節點,會一直保留下來。後面當另一個 NameNode 選主成功之後,會注意到上一個 Active NameNode 遺留下來的這個節點,從而會對舊的 ActiveNameNode 進行 fencing

Hadoop ****的兩種 fencing 機制:

  1. sshfence:通過 SSH 登錄到目標機器上,執行命令將對應的進程殺死;

  2. shellfence:執行一個用戶自定義的 shell 腳本來將對應的進程隔離;

只有在成功地執行完成 fencing 之後,選主成功的 ActiveStandbyElector 纔會回調ZKFailoverController 的 becomeActive 方法將對應的 NameNode 轉換爲 Active 狀態,開始

對外提供服務。

NameNode 共享存儲實現

基於 QJM 的共享存儲系統的總體架構: 基於 QJM 的共享存儲系統主要用於保存EditLog,並不保存 FSImage 文件。 FSImage 文件還是在 NameNode 的本地磁盤上。

QJM共享存儲的基本思想來自於 Paxos 算法,採用多個稱爲 JournalNode 的節點組成的JournalNode 集羣來存儲 EditLog。每個 JournalNode 保存同樣的 EditLog 副本。

每次NameNode 寫 EditLog 的時候,除了向本地磁盤寫入 EditLog 之外,也會並行地向JournalNode 集羣之中的每一個 JournalNode 發送寫請求,只要大多數 (majority) 的

JournalNode 節點返回成功就認爲向 JournalNode 集羣寫入 EditLog 成功。如果有 N 臺JournalNode,那麼根據大多數的原則,最多可以容忍有 (N-1)/2 臺 JournalNode 節點掛掉。 基於 QJM 的共享存儲系統的數據同步機制: Active NameNode 和 StandbyNameNode 使用JouranlNode 集羣來進行數據同步的過程如圖所示, Active NameNode 首先把 EditLog 提交到 JournalNode 集羣,然後 Standby NameNode 再從 JournalNode 集羣定時同步 EditLog

  1. Active NameNode 提交 EditLog 到 JournalNode 集羣的過程實際上是同步阻塞的,但是並不需要所有的 JournalNode 都調用成功,只要大多數 JournalNode 調用成功就可以了。如果無法形成大多數,那麼就認爲提交 EditLog 失敗, NameNode 停止服務退出進程。

  2. 當 NameNode 進入 Standby 狀態之後,會啓動一個線程, 定期從 JournalNode 集羣上同步 EditLog,然後把同步的 EditLog 回放到內存之中的文件系統鏡像上 (並不會同時把EditLog 寫入到本地磁盤上)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章