Hadoop的高可用(HA)

轉(zhuǎn)載:adoop HA高可用解析以及腦裂問(wèn)題
Hadoop1.x:
Hadoop 的兩大核心組件 HDFS 的NameNode 和 JobTracker 都存在著單點(diǎn)問(wèn)題。
Hadoop2.x :
HDFS的NameNode 和 YARN的ResourceManger 的單點(diǎn)問(wèn)題可以解決。
SecondaryNameNode保存的狀態(tài)總是滯后于NameNode,所以這種方式難免會(huì)導(dǎo)致丟失部分?jǐn)?shù)據(jù),也可以解決。(NameNode和ResourceManger實(shí)現(xiàn)方式類似,前者更復(fù)雜)
下面主要講HDFS NameNode的高可用(下圖為HDFS NameNode 高可用架構(gòu)圖):

Hadoop NameNode HA

概念

Active NameNode 和 Standby NameNode:

兩臺(tái) NameNode 形成互備,一臺(tái)處于 Active 狀態(tài),為主 NameNode,另外一臺(tái)處于 Standby 狀態(tài),為備 NameNode,只有主 NameNode 才能對(duì)外提供讀寫服務(wù)。
Active NN負(fù)責(zé)集群中所有客戶端的操作;
Standby NN主要用于備用,它主要維持足夠的狀態(tài),如果必要,可以提供快速
的故障恢復(fù)。

FailoverController(主備切換器):

FailoverController 作為獨(dú)立的進(jìn)程運(yùn)行,對(duì) NameNode 的主備切換進(jìn)行總體控制。FailoverController 監(jiān)測(cè) NameNode 的健康狀況,在主 NameNode 故障時(shí)借助 Zookeeper 實(shí)現(xiàn)自動(dòng)的主備選舉和切換。

HealthMonitor :

心跳監(jiān)控(HealthMonitor)是一個(gè)周期性工作的后臺(tái)線程,它在循環(huán)中周期性的同HA服務(wù)進(jìn)心跳,負(fù)責(zé)跟蹤NameNode服務(wù)的健康狀況,并在健康狀況變化時(shí)調(diào)用failover控制器的回調(diào)方法。
HealthMonitor 主要負(fù)責(zé)檢測(cè) NameNode 的健康狀態(tài),如果檢測(cè)到 NameNode 的狀態(tài)發(fā)生變化,會(huì)回調(diào) ZKFC(ZKFailoverController) 的相應(yīng)方法進(jìn)行自動(dòng)的主備選舉。

ActiveStandbyElector

ActiveStandbyElector 主要負(fù)責(zé)完成自動(dòng)的主備選舉,內(nèi)部封裝了 Zookeeper 的處理邏輯,一旦 Zookeeper 主備選舉完成,會(huì)回調(diào) ZKFailoverController 的相應(yīng)方法來(lái)進(jìn)行 NameNode 的主備狀態(tài)切換。

共享存儲(chǔ)系統(tǒng):

共享存儲(chǔ)系統(tǒng)是實(shí)現(xiàn) NameNode 的高可用最為關(guān)鍵的部分,共享存儲(chǔ)系統(tǒng)保存了 NameNode 在運(yùn)行過(guò)程中所產(chǎn)生的 HDFS 的元數(shù)據(jù)。主 NameNode 和備NameNode 通過(guò)共享存儲(chǔ)系統(tǒng)實(shí)現(xiàn)元數(shù)據(jù)同步。在進(jìn)行主備切換的時(shí)候,新的主 NameNode 在確認(rèn)元數(shù)據(jù)完全同步之后才能繼續(xù)對(duì)外提供服務(wù)。

Quorum-based 存儲(chǔ) + ZooKeeper:

備注:使用第三方的共享存儲(chǔ)系統(tǒng)(NAS/SAN)部署復(fù)雜,易出錯(cuò),無(wú)法有效解決腦裂問(wèn)題,而且故障時(shí)需要手動(dòng)轉(zhuǎn)移

QJM

QJM(Quorum Journal Manager)是基于Paxos(基于消息傳遞的一致性算法)。Paxos算法是解決分布式環(huán)境中如何就某個(gè)值達(dá)成一致,基于消息傳遞的一致性算法,可用于狀態(tài)的同步服務(wù);
QJM(Quorum Journal Manager)是Hadoop專門為Namenode共享存儲(chǔ)開發(fā)的組件。其集群運(yùn)行一組Journal Node,每個(gè)Journal 節(jié)點(diǎn)暴露一個(gè)簡(jiǎn)單的RPC接口,允許Namenode讀取和寫入數(shù)據(jù),數(shù)據(jù)存放在Journal節(jié)點(diǎn)的本地磁盤。當(dāng)Namenode寫入edit log時(shí),它向集群的所有Journal Node發(fā)送寫入請(qǐng)求,當(dāng)多數(shù)節(jié)點(diǎn)回復(fù)確認(rèn)成功寫入之后,edit log就認(rèn)為是成功寫入。例如有3個(gè)Journal Node,Namenode如果收到來(lái)自2個(gè)節(jié)點(diǎn)的確認(rèn)消息,則認(rèn)為寫入成功。

而在故障自動(dòng)轉(zhuǎn)移的處理上,引入了監(jiān)控Namenode狀態(tài)的ZookeeperFailController(ZKFC)。ZKFC一般運(yùn)行在Namenode的宿主機(jī)器上,與Zookeeper集群協(xié)作完成故障的自動(dòng)轉(zhuǎn)移。整個(gè)集群架構(gòu)圖如下:

實(shí)現(xiàn)方式:

(1) 初始化后,Active把editlog日志寫到2N+1上JN上,每個(gè)editlog有一個(gè)編號(hào),每次寫editlog只要其中大多數(shù)JN返回成功(即大于等于N+1)即認(rèn)定寫成功。

edit log數(shù)據(jù)保存在Journal Node本地磁盤,該路徑在配置中使用dfs.journalnode.edits.dir屬性指定。

(2) Standby定期從JN讀取一批editlog,并應(yīng)用到內(nèi)存中的FsImage中。

(3) 如何fencing: NameNode每次寫Editlog都需要傳遞一個(gè)編號(hào)Epoch給JN,JN會(huì)對(duì)比Epoch,如果比自己保存的Epoch大或相同,則可以寫,JN更新自己的Epoch到最新,否則拒絕操作。在切換時(shí),Standby轉(zhuǎn)換為Active時(shí),會(huì)把Epoch+1,這樣就防止即使之前的NameNode向JN寫日志,也會(huì)失敗。

(4) 寫日志:

  • (a) NN通過(guò)RPC向N個(gè)JN異步寫Editlog,當(dāng)有N/2+1個(gè)寫成功,則本次寫成功。
  • (b) 寫失敗的JN下次不再寫,直到調(diào)用滾動(dòng)日志操作,若此時(shí)JN恢復(fù)正常,則繼續(xù)向其寫日志。
  • (c) 每條editlog都有一個(gè)編號(hào)txid,NN寫日志要保證txid是連續(xù)的,JN在接收寫日志時(shí),會(huì)檢查txid是否與上次連續(xù),否則寫失敗。

(5) 讀日志:

  • (a) 定期遍歷所有JN,獲取未消化的editlog,按照txid排序。
  • (b) 根據(jù)txid消化editlog。

(6) 切換時(shí)日志恢復(fù)機(jī)制

  • (a) 主從切換時(shí)觸發(fā)
  • (b) 準(zhǔn)備恢復(fù)(prepareRecovery),standby向JN發(fā)送RPC請(qǐng)求,獲取txid信息,并對(duì)選出最好的JN。
  • (c) 接受恢復(fù)(acceptRecovery),standby向JN發(fā)送RPC,JN之間同步Editlog日志。
  • (d) Finalized日志。即關(guān)閉當(dāng)前editlog輸出流時(shí)或滾動(dòng)日志時(shí)的操作。
  • (e) Standby同步editlog到最新

(7) 如何選取最好的JN

  • (a) 有Finalized的不用in-progress
  • (b) 多個(gè)Finalized的需要判斷txid是否相等
  • (c) 沒(méi)有Finalized的首先看誰(shuí)的epoch更大
  • (d) Epoch一樣則選txid大的。

DataNode 節(jié)點(diǎn):

DataNode 會(huì)同時(shí)向主 NameNode 和備 NameNode 上報(bào)數(shù)據(jù)塊的位置信息。共享 HDFS 的元數(shù)據(jù)信息以及共享HDFS的數(shù)據(jù)塊和DataNode之間的映射關(guān)系。

NameNode主備切換過(guò)程

NameNode 主備切換主要由 ZKFailoverController、HealthMonitor 和 ActiveStandbyElector 這 3 個(gè)組件來(lái)協(xié)同實(shí)現(xiàn):
ZKFailoverController 作為 NameNode 機(jī)器上一個(gè)獨(dú)立的進(jìn)程啟動(dòng) (在 hdfs 啟動(dòng)腳本之中的進(jìn)程名為 zkfc),啟動(dòng)的時(shí)候會(huì)創(chuàng)建 HealthMonitor 和 ActiveStandbyElector 這兩個(gè)主要的內(nèi)部組件,ZKFailoverController 在創(chuàng)建 HealthMonitor 和 ActiveStandbyElector 的同時(shí),也會(huì)向 HealthMonitor 和 ActiveStandbyElector 注冊(cè)相應(yīng)的回調(diào)方法。

NameNode 實(shí)現(xiàn)主備切換的流程如圖所示,有以下幾步:

img

NameNode 主備過(guò)程.png

HealthMonitor 初始化完成后會(huì)啟動(dòng)內(nèi)部的線程來(lái)定時(shí)調(diào)用對(duì)應(yīng) NameNode 的 HAServiceProtocol RPC 接口的方法,對(duì) NameNode 的健康狀態(tài)進(jìn)行檢測(cè)。
HealthMonitor 如果檢測(cè)到 NameNode 的健康狀態(tài)發(fā)生變化,會(huì)回調(diào) ZKFailoverController 注冊(cè)的相應(yīng)方法進(jìn)行處理。
如果 ZKFailoverController 判斷需要進(jìn)行主備切換,會(huì)首先使用ActiveStandbyElector 來(lái)進(jìn)行自動(dòng)的主備選舉。
ActiveStandbyElector 與 Zookeeper 進(jìn)行交互完成自動(dòng)的主備選舉。
ActiveStandbyElector 在主備選舉完成后,會(huì)回調(diào) ZKFailoverController 的相應(yīng)方法來(lái)通知當(dāng)前的 NameNode 成為主 NameNode 或備 NameNode。
ZKFailoverController 調(diào)用對(duì)應(yīng) NameNode 的 HAServiceProtocol RPC 接口的方法將 NameNode 轉(zhuǎn)換為 Active 狀態(tài)或 Standby 狀態(tài)。

腦裂(split-brain)

腦裂(split-brain),指在一個(gè)高可用(HA)系統(tǒng)中,當(dāng)聯(lián)系著的兩個(gè)節(jié)點(diǎn)斷開聯(lián)系時(shí),本來(lái)為一個(gè)整體的系統(tǒng),分裂為兩個(gè)獨(dú)立節(jié)點(diǎn),這時(shí)兩個(gè)節(jié)點(diǎn)開始爭(zhēng)搶共享資源,結(jié)果會(huì)導(dǎo)致系統(tǒng)混亂,數(shù)據(jù)損壞。

腦裂問(wèn)題處理:

共享存儲(chǔ)的fencing,確保只有一個(gè)NN能寫成功。使用QJM實(shí)現(xiàn)fencing,下文敘述原理。
DataNode的fencing,確保只有一個(gè)NN能命令DN。HDFS-1972中詳細(xì)描述了DN如何實(shí)現(xiàn)fencing。

HDFS-1972是對(duì)hdfs修改的某些bug或則增加的功能

(1) 每個(gè)NN改變狀態(tài)的時(shí)候,向DN發(fā)送自己的狀態(tài)和一個(gè)序列號(hào)。
(2) DN在運(yùn)行過(guò)程中維護(hù)此序列號(hào),當(dāng)主備切換時(shí),新的NN在返回DN心跳時(shí)會(huì)返回自己的active狀態(tài)和一個(gè)更大的序列號(hào)。DN接收到這個(gè)返回是認(rèn)為該NN為新的active。
(3) 如果這時(shí)原來(lái)的active(比如GC)恢復(fù),返回給DN的心跳信息包含active狀態(tài)和原來(lái)的序列號(hào),這時(shí)DN就會(huì)拒絕這個(gè)NN的命令。

此外HDFS-1972中還解決了一些有可能導(dǎo)致誤刪除block的隱患,在failover后,active在DN匯報(bào)所有刪除報(bào)告前不應(yīng)該刪除任何block。

客戶端fencing,確保只有一個(gè)NN能響應(yīng)客戶端請(qǐng)求。讓訪問(wèn)standby NN的客戶端直接失敗。在RPC層封裝了一層,通過(guò)FailoverProxyProvider以重試的方式連接NN。通過(guò)若干次連接一個(gè)NN失敗后嘗試連接新的NN,對(duì)客戶端的影響是重試的時(shí)候增加一定的延遲。客戶端可以設(shè)置重試此時(shí)和時(shí)間。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容