HDFS HA 原理
標(biāo)簽:HDFS HA
概述
在 Hadoop 2.x 版本中木羹,Hadoop 實(shí)現(xiàn)了 HDFS 的 HA 功能材鹦,從而解決了 HDFS 中 NameNode 單點(diǎn)問題羔味。
在 HDFS NameNode 的高可用架構(gòu)中涉及到了多個(gè)部分叉抡,主要包括:Active NameNode匿醒、Standby NameNode毫炉、ZKFailoverController、ZooKeeper集群和共享存儲(chǔ)系統(tǒng)果港。其中沦泌,Active NameNode 和 Standby NameNode 互為主備,通過共享存儲(chǔ)系統(tǒng)共享同一份元數(shù)據(jù)辛掠,由 ZooKeeper 集群負(fù)責(zé)選取主 NameNode谢谦。ZKFailoverController 負(fù)責(zé)監(jiān)控 NameNode 的狀態(tài),當(dāng)主 NameNode 出現(xiàn)故障后萝衩,進(jìn)行主備切換回挽。
下面就對(duì) HDFS 的 HA 做進(jìn)一步的介紹。
共享存儲(chǔ)系統(tǒng)
共享存儲(chǔ)系統(tǒng)可以說是 HDFS HA 中最重要的一個(gè)部分猩谊,因?yàn)橹鱾?NameNode 需要通過共享存儲(chǔ)系統(tǒng)進(jìn)行元數(shù)據(jù)的實(shí)時(shí)同步千劈,這樣才能保證在進(jìn)行主備切換的時(shí)候,備 NameNode 上的元數(shù)據(jù)和主 NameNode 上的是一致的牌捷,確保切換之后不會(huì)丟失數(shù)據(jù)墙牌。
在 Hadoop 社區(qū)中曾經(jīng)出現(xiàn)過多種 NameNode 共享存儲(chǔ)解決方案,但現(xiàn)在 Hadoop 中默認(rèn)的實(shí)現(xiàn)是基于 QJM(Quorum Journal Manager)暗甥,因此我們這里只對(duì) QJM 的實(shí)現(xiàn)方式進(jìn)行介紹喜滨。
NameNode 元數(shù)據(jù)
在介紹具體的 QJM 實(shí)現(xiàn)之前,先對(duì) NameNode 的元數(shù)據(jù)文件做一個(gè)簡(jiǎn)單的介紹撤防。
NameNode 的元數(shù)據(jù)文件中最主要的是兩類文件:Fsimage 和 EditLog虽风,這兩種文件一起構(gòu)成了 NameNode 內(nèi)存中的文件系統(tǒng)鏡像。
FSImage
FSImage 是 NameNode 內(nèi)存中文件系統(tǒng)鏡像的一個(gè)快照寄月,在 NameNode 啟動(dòng)的時(shí)候辜膝,會(huì)先把 FSImage 加載到內(nèi)存中形成文件系統(tǒng)鏡像。FSImage 是由 NameNode 生成漾肮,保存在本地磁盤上厂抖,文件名形如 fsimage_${end_txid},其中 ${end_txid} 表示這個(gè) fsimage 文件的結(jié)束事務(wù) id初橘。
EditLog
EditLog 中保存了客戶端對(duì) HDFS 系統(tǒng)的所有更新操作验游,記錄在 EditLog 中的每個(gè)操作稱為一個(gè)事務(wù),每個(gè)事務(wù)都有一個(gè)整數(shù)形式的事務(wù) id 作為編號(hào)保檐。
EditLog 文件會(huì)被分割為很多段耕蝉,每一段稱為一個(gè) Segment,而 Segment 可以分為兩種:一種是處于正在寫入狀態(tài)的夜只,文件名形如 edits_inprogress_${start_txid}
,其中 ${start_txid}
表示這個(gè) Segment 的起始事務(wù) id垒在;另一種是處于寫入完成狀態(tài)的,文件名形如 edits_${start_txid}-${end_txid}
扔亥,其中 ${start_txid}
表示起始事務(wù) id场躯,${end_txid}
表示結(jié)束事務(wù) id。
在介紹完了 NameNode 的元數(shù)據(jù)文件之后旅挤,現(xiàn)在來介紹 NameNode 是如何通過 QJM 實(shí)現(xiàn)元數(shù)據(jù)共享的踢关。
元數(shù)據(jù)共享
HDFS 是通過 QJM 來實(shí)現(xiàn)的 NameNode 元數(shù)據(jù)的共享,但需要注意的是粘茄,QJM 上只保存了 EditLog 文件签舞,F(xiàn)SImage 文件還是保存在 NameNode 的本地磁盤上。
QJM 系統(tǒng)的基本思想是來源于 Paxos 算法柒瓣,由多個(gè)被稱為 Journal Node 的節(jié)點(diǎn)組成儒搭,每個(gè) Journal Node 上都保存了相同的數(shù)據(jù)。當(dāng)向 QJM 中寫入數(shù)據(jù)時(shí)芙贫,只有向超過半數(shù)的 Journal Node 上都寫入成功時(shí)才認(rèn)為寫入成功搂鲫。
每當(dāng)客戶端通過 Active NameNode 對(duì) HDFS 進(jìn)行更新操作時(shí),Active NameNode 都會(huì)將此次操作同時(shí)寫入本地磁盤和 QJM 上的 EditLog 文件磺平。而 Standby NameNode 則會(huì)定時(shí)從 QJM 上獲取 EditLog 文件魂仍,然后把同步的 EditLog 放到內(nèi)存中的文件系統(tǒng)鏡像中,以保持自身內(nèi)存中的元數(shù)據(jù)跟 Active NameNode 同步褪秀。
如果 Active NameNode 向 QJM 寫入 EditLog 失斝罘獭(也就是沒有滿足超過半數(shù)的 Journal Node 返回成功),那么 Active NameNode 會(huì)退出進(jìn)程媒吗,然后等待 Standby NameNode 接管后進(jìn)行數(shù)據(jù)恢復(fù)仑氛。
Standby NameNode 除了定時(shí)從 QJM 同步 EditLog 之外,還會(huì)定期對(duì)內(nèi)存中的文件系統(tǒng)鏡像做 checkpoint闸英,然后將生成的 FSImage 文件傳給 Active NameNode锯岖。Active NameNode 收到 Standby NameNode 發(fā)送的 FSImage 之后,會(huì)將本地舊的 FSImage 文件刪除甫何。
這樣出吹,通過 QJM,主備 NameNode 實(shí)現(xiàn)了元數(shù)據(jù)的同步辙喂,那么當(dāng)主備進(jìn)行切換的時(shí)候捶牢,他們之間又是如何進(jìn)行交互的呢鸠珠?
主備切換
當(dāng) Active NameNode 出現(xiàn)故障異常退出的時(shí)候,需要保證在 Standby NameNode 切換成 Active 狀態(tài)后元數(shù)據(jù)與 Active NameNode 保持一致秋麸。但是從之前的介紹中可以得知渐排,Standby NameNode 是定時(shí)從 QJM 上獲取 EditLog 文件,那么當(dāng) Active NameNode 出現(xiàn)故障時(shí)灸蟆,Standby NameNode 上的數(shù)據(jù)并不是嚴(yán)格同步的驯耻。
同時(shí),當(dāng) Active NameNode 出現(xiàn)故障時(shí)炒考,也無法保證 QJM 上的數(shù)據(jù)是一致的可缚。考慮這樣一種情況斋枢,假設(shè) QJM 中有 3 個(gè)節(jié)點(diǎn)帘靡,Active NameNode 在分別向這三個(gè)節(jié)點(diǎn)發(fā)送完寫入命令后崩潰退出了,此時(shí)只有一個(gè) Journal Node 寫入成功瓤帚,而其他兩個(gè) Journal Node 寫入失敗测柠。那么此時(shí) QJM 就處于一個(gè)數(shù)據(jù)不一致的狀態(tài),在這種情況下就需要對(duì) QJM 上的數(shù)據(jù)進(jìn)行恢復(fù)缘滥,使其達(dá)到一致性狀態(tài)轰胁。
綜上所述,在發(fā)生主備切換 Standby NameNode 切換為 Active 狀態(tài)后朝扼,需要先對(duì) QJM 進(jìn)行數(shù)據(jù)恢復(fù)赃阀,然后進(jìn)行數(shù)據(jù)同步,只有執(zhí)行完這兩個(gè)操作之后擎颖,Standby NameNode 才能對(duì)外提供服務(wù)榛斯。
下面對(duì)這兩個(gè)過程做一個(gè)簡(jiǎn)單的介紹。
QJM 的數(shù)據(jù)恢復(fù)
首先搂捧,需要明確的是驮俗,數(shù)據(jù)恢復(fù)肯定是發(fā)生在 Standby NameNode 成為 Active 之后。那么在新的 Active NameNode 被選舉出來之后允跑,需要更新所有 Journal Node 上的 Epoch(可以將 Epoch 理解成每一次主備切換的標(biāo)識(shí)符王凑,是一個(gè)全局唯一的順序遞增的整數(shù))。
其次聋丝,需要進(jìn)行數(shù)據(jù)恢復(fù)的肯定是 QJM 上最后一個(gè) EditLog Segment 文件索烹,因?yàn)?Active NameNode 在異常退出前寫入的肯定是最新的 EditLog 文件。每個(gè) Journal Node 上最后的 EditLog Segment 的起始事務(wù) id 會(huì)在更新完 Epoch 后返回給 Active NameNode弱睦,而 Active NameNode 則是從所有 Journal Node 返回的 Epoch 中選取最大的一個(gè)作為數(shù)據(jù)恢復(fù)的基準(zhǔn)數(shù)據(jù)源百姓。
Active NameNode 將數(shù)據(jù)恢復(fù)的基準(zhǔn)數(shù)據(jù)源所在的 Journal Node 信息發(fā)送給其他所有 Journal Node 之后,其他的節(jié)點(diǎn)會(huì)從該數(shù)據(jù)源所在節(jié)點(diǎn)上下載 EditLog Segment 文件况木,將本地的文件替換掉垒拢。
數(shù)據(jù)同步
在完成了數(shù)據(jù)恢復(fù)的過程后旬迹,此時(shí) QJM 上的數(shù)據(jù)已經(jīng)達(dá)到了一致狀態(tài),而且與 Active NameNode 退出前的數(shù)據(jù)一致求类。此時(shí)新的 Active NameNode 只需要將 QJM 上未同步的 EditLog 文件同步到本地舱权,加載到內(nèi)存中后就可以達(dá)到與舊的 Active NameNode 完全一致的元數(shù)據(jù)狀態(tài)。
而新的 Active NameNode 從 QJM 上同步數(shù)據(jù)的過程和 Standby NameNode 定時(shí)從 QJM 上同步 EditLog 的實(shí)現(xiàn)是一樣的仑嗅。
主備切換實(shí)現(xiàn)
在介紹了共享存儲(chǔ)系統(tǒng)之后,下面就可以來介紹主備 NameNode 在發(fā)生故障切換時(shí)的具體過程张症。
NameNode 的主備切換主要由 ZKFailoverController仓技、HealthMonitor 和 ActiveStandbyElector 這三個(gè)組件協(xié)同實(shí)現(xiàn)。
首先簡(jiǎn)單介紹下這三個(gè)組件的作用俗他。
ZKFailoverController
ZKFailoverController 作為 NameNode 上的一個(gè)獨(dú)立進(jìn)程啟動(dòng)(zkfc 進(jìn)程)脖捻,啟動(dòng)的時(shí)候會(huì)創(chuàng)建 HealthMonitor 和 ActiveStandbyElector 這兩個(gè)線程。ZKFailoverController 在創(chuàng)建了這兩個(gè)線程的時(shí)候兆衅,同時(shí)也向 HealthMonitor 和 ActiveStandbyElector 注冊(cè)了相應(yīng)的回調(diào)方法地沮。
HeathMonitor
HealthMonitor 主要負(fù)責(zé)監(jiān)測(cè) NameNode 的健康狀態(tài),如果發(fā)現(xiàn) NameNode 的狀態(tài)發(fā)生了變化羡亩,那么會(huì)調(diào)用 ZKFailoverController 的回調(diào)方法進(jìn)行自動(dòng)的主備選舉摩疑。
ActiveStandbyElector
ActiveStandbyElector 主要負(fù)責(zé)進(jìn)行自動(dòng)的主備選舉,內(nèi)部封裝了 ZooKeeper 的處理邏輯畏铆。一旦 ZooKeeper 上對(duì) NameNode 的主備選舉完成雷袋,ActiveStandbyElector 會(huì)調(diào)用 ZKFailoverController 的回調(diào)方法來進(jìn)行 NameNode 的主備切換。
在介紹完了這三個(gè)組件之后辞居,就可以來介紹具體的主備切換過程了楷怒。
具體過程
NameNode 的主備切換過程大體過程如下:
- HealthMonitor 在初始化完成后,會(huì)啟動(dòng)內(nèi)部的線程來定時(shí)監(jiān)測(cè) NameNode 的健康狀態(tài)瓦灶。
- HealthMonitor 如果發(fā)現(xiàn) NameNode 的狀態(tài)發(fā)生了改變鸠删,則會(huì)回調(diào) ZKFailoverController 注冊(cè)的方法進(jìn)行處理。
- 如果 ZKFailoverController 判斷需要進(jìn)行主備切換贼陶,則會(huì)使用 ActiveStandbyElector 來進(jìn)行自動(dòng)的主備選舉刃泡。
- ActiveStandbyElector 與 ZooKeeper 進(jìn)行交互,完成自動(dòng)的主備選舉碉怔。
- ActiveStandbyElector 在完成主備選舉后捅僵,會(huì)回調(diào) ZKFailoverController 注冊(cè)的方法,通知 ZKFailoverController 當(dāng)前的 NameNode 成為主或備眨层。
- ZKFailoverController 在接收到 ActiveStandbyElector 的通知后調(diào)用對(duì)應(yīng) NameNode 的接口庙楚,將 NameNode 轉(zhuǎn)換為 Active 或 Standby 狀態(tài)。