前言
Hadoop2.0之前,NameNode是單個集群的故障點,NameNode作為集群首腦,存放著集群中所有的元數(shù)據(jù),一旦節(jié)點出錯,將導(dǎo)致整個集群不可用。為了解決這個問題,HA(高可用)就被引入了。
HA中的角色如下
1.ZKFC
ZKFC即ZKFailoverController,作為獨立進(jìn)程存在,負(fù)責(zé)控制NameNode的主備切換,ZKFC會監(jiān)測NameNode的健康狀況,當(dāng)發(fā)現(xiàn)Active NameNode出現(xiàn)異常時會通過Zookeeper集群進(jìn)行一次主備選舉,完成Active和Standby狀態(tài)的切換;
2.HealthMonitor
定時調(diào)用NameNode的HAServiceProtocol RPC接口(monitorHealth和getServiceStatus),監(jiān)控NameNode的健康狀態(tài)并向ZKFC反饋;
3.ActiveStandbyElector
接收ZKFC的選舉請求,通過Zookeeper自動完成主備選舉,選舉完成后回調(diào)ZKFC的主備切換方法對NameNode進(jìn)行Active和Standby狀態(tài)的切換;
4.JouranlNode集群
共享存儲系統(tǒng),負(fù)責(zé)存儲HDFS的元數(shù)據(jù),Active NameNode(寫入)和Standby NameNode(讀取)通過共享存儲系統(tǒng)實現(xiàn)元數(shù)據(jù)同步,在主備切換過程中,新的Active NameNode必須確保元數(shù)據(jù)同步完成才能對外提供服務(wù);
一.Namenode HA的思考**
為什么要Namenode HA?
解決NameNode單點故障問題,NameNode 很重要,掛掉會導(dǎo)致存儲停止服務(wù),無法進(jìn)行數(shù)據(jù)的讀寫,基于此NameNode的計算(MR,Hive等)也無法完成。
Namenode HA 如何實現(xiàn),關(guān)鍵技術(shù)難題是什么?
1.數(shù)據(jù)同步問題
如何保持主和備NameNode的狀態(tài)同步,并讓Standby在Active掛掉后迅速提供服務(wù),namenode啟動比較耗時,包括加載fsimage和editlog(獲取file to block信息),處理所有datanode第一次blockreport(獲取block to datanode信息),保持NN的狀態(tài)同步,需要這兩部分信息同步。
防止腦裂
指在一個高可用(HA)系統(tǒng)中,當(dāng)聯(lián)系著的兩個節(jié)點斷開聯(lián)系時,本來為一個整體的系統(tǒng),分裂為兩個獨立節(jié)點,這時兩個節(jié)點開始爭搶共享資源,結(jié)果會導(dǎo)致系統(tǒng)混亂,數(shù)據(jù)損壞。NameNode切換對外透明
主Namenode切換到另外一臺機(jī)器時,不應(yīng)該導(dǎo)致正在連接的客戶端失敗,主要包括Client,Datanode與NameNode的鏈接。
二.數(shù)據(jù)同步解決方案
1.客戶端的增刪改的元數(shù)據(jù)
數(shù)據(jù)在兩個NameNode間同步的過程中,不能因為追求強一致性,而采用同步,阻塞的方式,如果standby節(jié)點掛了,或者因為網(wǎng)絡(luò)通信阻塞的緣故,不能及時的返回,那么NameNode將長時間都處于阻塞狀態(tài),高可用性就受到了破壞。
但是如果采用異步方式處理,數(shù)據(jù)的一致性又無法得到保障,因為可能元數(shù)據(jù)同步到一半,Active NameNode掛了,這時進(jìn)行故障轉(zhuǎn)移,兩臺NN的數(shù)據(jù)是不一致的。
這種問題可以使用類似于消息隊列中的解決方案,在HDFS中,我們常用以下兩種方式解決:
1)基于NFS共享存儲解決方案
Active NN與Standby NN通過NFS實現(xiàn)共享數(shù)據(jù),但如果Active NN與NFS之間或Standby NN與NFS之間,其中一處有網(wǎng)絡(luò)故障的話,那就會造成數(shù)據(jù)同步問題
2)基于Qurom Journal Manager(QJM)解決方案
這是一個基于Paxos算法實現(xiàn)的HDFS HA方案,它給出了一種較好的解決思路和方案。在這里主要介紹一下QJM解決方案。

①Active NN、Standby NN有主備之分,NN Active是主的,NN Standby備用的,集群啟動之后,一個NameNode是Active狀態(tài),來處理client的請求;
②Active NN與Standby NN之間是通過一組JN(JournalNodes)共享數(shù)據(jù)(JN一般為奇數(shù)個,ZK一般也為奇數(shù)個,過半寫成功策略),Active NN會把日志文件EditLog寫到JN中去,只要JN中有一半寫成功(并行的),那就表明Active NN向JN中寫成功,數(shù)據(jù)不會丟失了。當(dāng)然這個算法所能容忍的是多有N臺機(jī)器掛掉,如果多于N臺掛掉,這個算法就失效了。這個原理是基于Paxos算法。
③在HA架構(gòu)里面SecondaryNameNode這個冷備角色已經(jīng)不存在了,為了保持standbyNN時時的與主ActiveNN的元數(shù)據(jù)保持一致,他們之間交互通過一系列守護(hù)的輕量級進(jìn)程JournalNode。Standby NN開始從JN中讀取數(shù)據(jù),來實現(xiàn)與Active NN數(shù)據(jù)同步。
④當(dāng)發(fā)生故障時,Active的NN掛掉后,StandbyNN會在它成為ActiveNN前,讀取所有的JN里面的修改日志,這樣就能高可靠的保證與掛掉的NN的目錄鏡像樹一致,然后無縫的接替它的職責(zé),維護(hù)來自客戶端請求,從而達(dá)到一個高可用的目的。
⑤JN不會因為其中一臺的延遲而影響整體的延遲,而且也不會因為JN的數(shù)量增多而影響性能(因為NN向JN發(fā)送日志是并行的)
2.block的location信息
為了實現(xiàn)Standby NN在Active NN掛掉之后,能迅速的再提供服務(wù),需要DN不僅需要向Active NN匯報,同時還要向Standby NN匯報,這樣就使得Standby NN能保存數(shù)據(jù)塊在DN上的位置信息,因為在NameNode在啟動過程中最費時工作,就是處理所有DN上的數(shù)據(jù)塊的信息。
三.如何避免腦裂問題
1.ZKFC處理的機(jī)制
在分布式系統(tǒng)中腦裂又稱為雙主現(xiàn)象,由于Zookeeper的“假死”,長時間的垃圾回收或其它原因都可能導(dǎo)致雙Active NameNode現(xiàn)象,此時兩個NameNode都可以對外提供服務(wù),無法保證數(shù)據(jù)一致性。對于生產(chǎn)環(huán)境,這種情況的出現(xiàn)是毀滅性的,必須通過自帶的隔離(Fencing)機(jī)制預(yù)防這種現(xiàn)象的出現(xiàn)。
ActiveStandbyElector為了實現(xiàn)fencing隔離機(jī)制,在成功創(chuàng)建hadoop-ha/dfs.nameservices/ActiveStandbyElectorLock臨時節(jié)點后,會創(chuàng)建另外一個/hadoop?ha/dfs.nameservices/ActiveBreadCrumb持久節(jié)點,這個持久節(jié)點保存了Active NameNode的地址信息。
當(dāng)Active NameNode在正常的狀態(tài)下斷開Zookeeper 回話(注意由于ActiveStandbyElectorLock是臨時節(jié)點,也會隨之刪除),會一起刪除持久節(jié)點ActiveBreadCrumb。但是如果ActiveStandbyElector在異常的狀態(tài)下關(guān)閉Zookeeper Session,那么由于ActiveBreadCrumb是持久節(jié)點,會一直保留下來。當(dāng)另一個NameNode選主成功之后,會注意到上一個Active NameNode遺留下來的ActiveBreadCrumb節(jié)點,從而會回調(diào)ZKFailoverController的方法對舊的Active NameNode進(jìn)行fencing。
① 首先ZKFC會嘗試調(diào)用舊Active NameNode的HAServiceProtocol RPC接口的transitionToStandby方法,看能否將狀態(tài)切換為Standby;
② 如果調(diào)用transitionToStandby方法切換狀態(tài)失敗,那么就需要執(zhí)行Hadoop自帶的隔離措施,Hadoop目前主要提供兩種隔離措施:
sshfence:SSH to the Active NameNode and kill the process;
shellfence:run an arbitrary shell command to fence the Active NameNode;
只有在成功地執(zhí)行完成fencing之后,選主成功的ActiveStandbyElector才會回調(diào)ZKFC的becomeActive方法將對應(yīng)的NameNode切換為Active,開始對外提供服務(wù)。
2.JournalNodes的Fencing機(jī)制
簡單地理解如下:每個NameNode 與 JournalNodes通信時,需要帶一個 epoch numbers(epoch numbers 是唯一的且只增不減)。而每個JournalNode 都有一個本地的promised epoch。
擁有值大的epoch numbers 的NameNode會使得JournalNode提升自己的 promised epoch,從而占大多數(shù),而epoch numbers較小的那個NameNode就成了少數(shù)派(Paxos協(xié)議思想)。
從而epoch number值大的NameNode才是真正的Active NameNode,擁有寫JournalNode的權(quán)限。注意:(任何時刻只允許一個NameNode擁有寫JournalNode權(quán)限)
3.datanode的fencing
確保只有一個NN能命令DN
(1)每個NN改變狀態(tài)的時候,向DN發(fā)送自己的狀態(tài)和一個序列號
(2)DN在運行過程中維護(hù)此序列號,當(dāng)failover時,新的NN在返回DN心跳時會返回自己的active狀態(tài)和一個更大的序列號。DN接收到這個返回則認(rèn)為該NN為新的active
(3)如果這時原來的activeNN恢復(fù),返回給DN的心跳信息包含active狀態(tài)和原來的序列號,這時DN就會拒絕這個NN的命令。
4.客戶端fencing
(1)確保只有一個NN能響應(yīng)客戶端請求,讓訪問standby 的NN的客戶端直接失敗。
(2)在RPC層封裝了一層,通過FailoverProxyProvider以重試的方式連接NN。通過若干次連接一個NN失敗后嘗試連接新的NN,對客戶端的影響是重試的時候增加一定的延遲。客戶端可以設(shè)置重試此時和時間。
四.ZKFC簡介
Hadoop提供了ZKFailoverController角色,作為一個deamon進(jìn)程,簡稱zkfc。zkfc是Zookeeper的客戶端,部署在每個NameNode的節(jié)點上。
ZKFC的作用如下:
1、健康監(jiān)測:周期性的向它監(jiān)控的NN發(fā)送健康探測命令,從而來確定某個NameNode是否處于健康狀態(tài),如果機(jī)器宕機(jī),心跳失敗,那么zkfc就會標(biāo)記它處于一個不健康的狀態(tài)。
2、會話管理:如果NN是健康的,zkfc就會在zookeeper中保持一個打開的會話,如果NameNode同時還是Active狀態(tài)的,那么zkfc還會在Zookeeper中占有一個類型為短暫類型的znode,當(dāng)這個NN掛掉時,這個znode將會被刪除,然后備用的NN,將會得到這把鎖,升級為主NN,同時標(biāo)記狀態(tài)為Active。
3、當(dāng)宕機(jī)的NN新啟動時,它會再次注冊zookeper,發(fā)現(xiàn)已經(jīng)有znode鎖了,便會自動變?yōu)镾tandby狀態(tài),如此往復(fù)循環(huán),保證高可靠,需要注意,目前僅僅支持多配置2個NN
4、master選舉:如上所述,通過在zookeeper中維持一個短暫類型的znode,來實現(xiàn)搶占式的鎖機(jī)制,從而判斷那個NameNode為Active狀態(tài)。