利用Zookeeper實現HDFS HA方案
引言
-
在Hadoop 1.x版本,HDFS集羣的NameNode一直存在單點故障問題:
- 集羣只存在一個NameNode節點,它維護了HDFS所有的元數據信息
- 當該節點所在服務器宕機或者服務不可用,整個HDFS集羣處於不可用狀態
-
Hadoop 2.x版本提出了高可用 (High Availability, HA) 解決方案
用到的ZK特性
- 所有ZK服務器數據是相同的
- 臨時節點
- 臨時節點只在當前會話期存在,當前會話結束後,臨時節點自動刪除
- 持久節點
- 持久節點類似Linux的文件夾,會永久存在
- 監聽器的三個邏輯
- 註冊:客戶端向ZooKeeper集羣註冊監聽器
- 監聽事件:監聽器負責監聽特定的事件
- 回調函數:當監聽器監聽到事件的發生後,調用註冊監聽器時定義的回調函數
HDFS HA方案,主要分兩部分:
①元數據同步
②主備切換
HDFS HA實現之元數據備份
共享存儲系統
- NFS(Nnetwork File System):Linux共享文件系統,很少使用
- QJM(Quorum Journal Node):hadoop中的共享系統,用到比較多,下文會有介紹
節點功能劃分
- 在同一個HDFS集羣,運行兩個互爲主備的
NameNode
節點。 - 一臺爲
主Namenode
節點,處於Active
狀態,一臺爲備NameNode
節點,處於Standby
狀態。 - 爲了確保快速切換,standby狀態的NameNode有必要知道集羣中所有數據塊的位置。爲了做到這點,所有的
DN
必須配置兩個NN
的地址,發送數據塊位置信息
和心跳
給他們兩個 - 其中只有
Active NN
對外提供讀寫服務,standby
狀態的NN
有能力讀取JN
中的變更信息,並且一直監控edit log
的變化,把變化應用於自己的命名空間 Standby NameNode
會根據Active NameNode
的狀態變化,在必要時切換成Active
狀態。- JournalNode集羣
- 在主備切換過程中,新的Active NameNode必須確保與原Active NamNode
元數據同步
完成,才能對外提供服務 - 所以用
JournalNode
集羣作爲共享存儲
系統; - 當客戶端對HDFS做操作,會在
Active NN
中edits.log
文件中作日誌記錄,同時
日誌記錄也會寫入JournalNode
集羣;負責存儲HDFS新產生的元數據 - 當有新數據寫入JournalNode集羣時,
Standby NN
能監聽到此情況,將新數據同步過來 - Active NameNode(寫入)和Standby NameNode(讀取)實現元數據同步
- 在主備切換過程中,新的Active NameNode必須確保與原Active NamNode
HDFS HA實現之主備選舉
-
ZKFC涉及角色
- 每個NameNode節點上各有一個
ZKFC進程
- ZKFC即
ZKFailoverController
,作爲獨立進程存在,負責控制NameNode的主備切換
- ZKFC會監控NameNode的健康狀況,當發現Active NameNode異常時,通過Zookeeper集羣進行namenode主備選舉,完成
Active
和Standby
狀態的切換- ZKFC在啓動時,同時會初始化
HealthMonitor
和ActiveStandbyElector
服務 - ZKFC同時會向
HealthMonitor
和ActiveStandbyElector
註冊相應的回調方法(如上圖的①回調、②回調) - HealthMonitor定時調用NameNode的HAServiceProtocol RPC接口(monitorHealth和getServiceStatus),監控NameNode的健康狀態,並向ZKFC反饋
- ActiveStandbyElector接收ZKFC的選舉請求,通過Zookeeper自動完成namenode主備選舉
- 選舉完成後回調ZKFC的主備切換方法對NameNode進行Active和Standby狀態的切換
- ZKFC在啓動時,同時會初始化
- 每個NameNode節點上各有一個
-
主備選舉過程:
- 啓動兩個NameNode、ZKFC
- 兩個ZKFC通過各自ActiveStandbyElector發起NameNode的主備選舉,這個過程利用Zookeeper的
寫一致性
和臨時節點機制
實現 - 當發起一次主備選舉時,
ActiveStandbyElector
會嘗試在Zookeeper創建臨時節點/hadoop-ha/${dfs.nameservices}/ActiveStandbyElectorLock
,Zookeeper的寫一致性保證最終只會有一個
ActiveStandbyElector創建成功 - ActiveStandbyElector從ZooKeeper獲得選舉結果
創建成功
的 ActiveStandbyElector回調ZKFC的回調方法②,將對應的NameNode切換爲Active
NameNode狀態- 而
創建失敗
的ActiveStandbyElector回調ZKFC的回調方法②,將對應的NameNode切換爲Standby
NameNode狀態 - 不管是否選舉成功,
所有
ActiveStandbyElector都會在臨時節點
ActiveStandbyElectorLock上註冊
一個Watcher監聽器
,來監聽這個節點的狀態變化事件 - 如果
Active NN
對應的HealthMonitor檢測到NameNode狀態異常時,通知對應ZKFC - ZKFC會調用 ActiveStandbyElector 方法,
刪除
在Zookeeper上創建的臨時節點
ActiveStandbyElectorLock(或者ActvieStandbyElector與ZooKeeper的session斷開
,臨時節點也會被刪除,但有可能此時原Active NameNode仍然是active狀態,造成腦裂
,見下文) - 此時,
Standby NN
的ActiveStandbyElector註冊的Watcher
就會監聽到此節點的 NodeDeleted事件。 - 收到這個事件後,此ActiveStandbyElector發起主備選舉,成功創建
臨時節點
ActiveStandbyElectorLock,如果創建成功,則Standby NameNode被選舉爲Active NameNode(過程同上)
腦裂
-
腦裂在分佈式系統中
雙主現象
又稱爲腦裂- 由於
Active NN
的Session
斷開,而Active NN
的ZKFC又沒有檢測到異常,仍然認爲自己應該是Active狀態會造成腦裂 - 網絡故障,造成集羣分爲兩個部分也會造成腦裂,
- Zookeeper的“假死”、長時間的垃圾回收或其它原因都可能導致雙Active NameNode現象
- 由於
-
此時兩個
NameNode
都可以對外提供服務,無法保證數據一致性 -
隔離
對於生產環境,這種情況的出現是毀滅性的,必須通過自帶的**隔離(Fencing)**機制預防此類情況
處理HA中的腦裂
-
ActiveStandbyElector成功創建ActiveStandbyElectorLock臨時節點後,會創建另一個ActiveBreadCrumb
持久節點
-
ActiveBreadCrumb持久節點保存了Active NameNode的地址信息
-
當Active NameNode在正常的狀態下斷開Zookeeper Session,會一併刪除臨時節點ActiveStandbyElectorLock、持久節點ActiveBreadCrumb
-
但是如果ActiveStandbyElector在異常的狀態下關閉Zookeeper Session,那麼持久節點ActiveBreadCrumb會保留下來(此時有可能由於active NameNode與ZooKeeper通信不暢導致,所以此NameNode還處於active狀態)
-
當另一個NameNode要由standy變成active狀態時,會發現上一個Active NameNode遺留下來的ActiveBreadCrumb節點,那麼會回調ZKFailoverController的方法對舊的Active NameNode進行fencing
-
首先ZKFC會嘗試調用舊Active NameNode的HAServiceProtocol RPC接口的transitionToStandby方法,看能否將其狀態切換爲Standby
-
如果transitionToStandby方法切換狀態失敗,那麼就需要執行Hadoop自帶的隔離措施,Hadoop目前主要提供兩種隔離措施:
sshfence:SSH to the Active NameNode and kill the process;
shellfence:run an arbitrary shell command to fence the Active NameNode -
只有成功地fencing之後,選主成功的ActiveStandbyElector纔會回調ZKFC的becomeActive方法transitionToActive將對應的NameNode切換爲Active,開始對外提供服務
-