一. 概念
所謂HA间聊,即高可用(7*24小時(shí)不中斷服務(wù))
實(shí)現(xiàn)高可用最關(guān)鍵的是消除單點(diǎn)故障
hadoop-ha嚴(yán)格來說應(yīng)該分成各個(gè)組件的HA機(jī)制——HDFS的HA哎榴、YARN的HA
二. 機(jī)制詳解
1.保證高可用,為nameNode分配一個(gè)standBy的nameNode充尉,客戶端請(qǐng)求的還是ann驼侠,sbnn不接收客戶端請(qǐng)求倒源,ann和sbnn都接收datanode定時(shí)匯報(bào)的數(shù)據(jù)句狼,由此可以減少主備切換的時(shí)間腻菇。當(dāng)客戶端發(fā)出請(qǐng)求芜繁,ann收到進(jìn)行處理,將操作追加到edit日志蔬捷,更新日志周拐。
2.為了保證edit日志不至于在ann傻逼之后不可用妥粟,使用一個(gè)共享存儲(chǔ)系統(tǒng)勾给,在nn追加日志同時(shí)也將edit同步到這個(gè)共享存儲(chǔ)系統(tǒng)之中播急,存儲(chǔ)方案是Quorum Journal Manager桩警,即JournalNode集群昌妹。該集群有n個(gè)節(jié)點(diǎn),ann向jn集群同步edit數(shù)據(jù)谨胞,向每個(gè)節(jié)點(diǎn)都發(fā)送數(shù)據(jù)蒜鸡,成功與否遵循“多數(shù)原則”康聂。sbnn從共享存儲(chǔ)系統(tǒng)獲取editLog數(shù)據(jù)恬汁,對(duì)ann上的數(shù)據(jù)進(jìn)行共享氓侧。
JournalNode集群:基于zk實(shí)現(xiàn)导狡,多數(shù)原則(cap原則独郎,不保證數(shù)據(jù)完全一致性)為了讓Standby Node與Active Node保持同步枚赡,這兩個(gè)Node都與一組互相獨(dú)立的進(jìn)程保持通信(Journal Nodes)贫橙。當(dāng)Active Node上更新了Namespace,它將記錄修改日志發(fā)送給Journal Nodes疲迂。Standby noes將會(huì)從Journal Nodes中讀取這些Edits尤蒿。Standby Node將日志變更應(yīng)用在自己的Namespace中优质。當(dāng)Failover發(fā)生時(shí)军洼,Standby將會(huì)在提升自己為Active之前避乏,確保能夠從JNS中讀取所有的Edits甘桑。即在failover發(fā)生之前铆帽,Standy持有的namespace應(yīng)該與Active保持完全同步德谅。
4.ZKFailoverController(主備切換控制器愧驱,ZKFC):ZKFailoverController 作為獨(dú)立的進(jìn)程運(yùn)行组砚,對(duì) NameNode 的主備切換進(jìn)行總體控制糟红。ZKFailoverController 能及時(shí)檢測(cè)到 NameNode 的健康狀況改化,在主 NameNode 故障時(shí)借助 Zookeeper 實(shí)現(xiàn)自動(dòng)的主備選舉和切換(當(dāng)然 NameNode 目前也支持不依賴于 Zookeeper 的手動(dòng)主備切換)
FC 最初的目的是為了實(shí)現(xiàn) SNN 和 ANN 之間故障自動(dòng)切換,F(xiàn)C 是獨(dú)立與 NN 之外的故障切換控制器兄裂,ZKFC 作為 NameNode 機(jī)器上一個(gè)獨(dú)立的進(jìn)程啟動(dòng) 谈撒,它啟動(dòng)的時(shí)候會(huì)創(chuàng)建 HealthMonitor 和 ActiveStandbyElector 這兩個(gè)主要的內(nèi)部組件匾南,其中:
HealthMonitor:主要負(fù)責(zé)檢測(cè) NameNode 的健康狀態(tài)溯乒,如果檢測(cè)到 NameNode 的狀態(tài)發(fā)生變化夹厌,會(huì)回調(diào) ZKFailoverController 的相應(yīng)方法進(jìn)行自動(dòng)的主備選舉;
ActiveStandbyElector:主要負(fù)責(zé)完成自動(dòng)的主備選舉裆悄,內(nèi)部封裝了 Zookeeper 的處理邏輯矛纹,一旦 Zookeeper 主備選舉完成,會(huì)回調(diào) ZKFailoverController 的相應(yīng)方法來進(jìn)行 NameNode 的主備狀態(tài)切換光稼。
ActiveNameNode選舉:ZKFC啟動(dòng)的時(shí)候會(huì)在Zookeeper創(chuàng)建選舉節(jié)點(diǎn)(臨時(shí)的ZNode)或南,如果創(chuàng)建成功,ZKFC會(huì)告訴這個(gè)NameNode它就是active主節(jié)點(diǎn)艾君。另外一個(gè)ZKFC創(chuàng)建失敗采够,則與它綁定的NameNode就是standby備用節(jié)點(diǎn),創(chuàng)建失敗的那個(gè)ZKFC就監(jiān)控這個(gè)臨時(shí)節(jié)點(diǎn)的變化冰垄。(在zk上創(chuàng)建的節(jié)點(diǎn)其實(shí)相當(dāng)于一個(gè)鎖,誰獲取到誰就是ann,另一個(gè)是sbnn,當(dāng)ann出現(xiàn)問題感局,會(huì)通過刪除zk上的臨時(shí)節(jié)點(diǎn)的方式撑毛,釋放鎖斩个,此時(shí)sbnn就可以獲取到成為ann的資格)此外第一次啟動(dòng)的時(shí)候還會(huì)在Zookeeper上創(chuàng)建一個(gè)/hadoop-ha/{dfs.nameservices}/ActiveBreadCrumb的永久節(jié)點(diǎn),這個(gè)永久節(jié)點(diǎn)保存著當(dāng)前Active NameNode的信息,這么做是為了防止腦裂跟束。
對(duì)本機(jī)NameNode的Health監(jiān)控:初始化啟動(dòng)RPC服務(wù)温学,和nameNode建立服務(wù)連接轧拄。之后啟動(dòng)本機(jī)NameNode的Health監(jiān)控俐末,每個(gè)NameNode都會(huì)提供HAService服務(wù),對(duì)應(yīng)協(xié)議為org.apache.hadoop.ha.HAServiceProtocol甫题。HealthMonitor作為消費(fèi)方調(diào)用,來獲取NameNode的健康狀況秋泳。所有的操作觸發(fā)都是根據(jù)NameNode的健康狀況由HealthMonitor觸發(fā)的,可以說HealthMonitor是整個(gè)ZKFC服務(wù)的引擎。HealthMonitor內(nèi)部有一個(gè)守護(hù)線程MonitorDaemon变骡,它負(fù)責(zé)執(zhí)行NameNode的健康檢查并觸發(fā)相應(yīng)的操作蹬刷。
以上功能用來支持主備切換:
當(dāng)ActiveNN出現(xiàn)問題迂卢,對(duì)其進(jìn)行監(jiān)控的ZKFC進(jìn)程會(huì)刪除zk上的臨時(shí)節(jié)點(diǎn)怔毛,這樣sbnn的ZKFC就會(huì)拿到ann失敗的信息奸晴,然后獲取active“鎖”寄啼,通過rpc調(diào)用,通知sbnn成為ann。
為了防止腦裂
ps:何為腦裂梢卸?一個(gè)集群兩個(gè)大腦
NameNode 在垃圾回收(GC)時(shí),可能會(huì)在長(zhǎng)時(shí)間內(nèi)整個(gè)系統(tǒng)無響應(yīng)喜庞,因此,也就無法向 zk 寫入心跳信息猖吴,這樣的話可能會(huì)導(dǎo)致臨時(shí)節(jié)點(diǎn)掉線刑然,備 NameNode 會(huì)切換到 Active 狀態(tài)寺擂,這種情況,可能會(huì)導(dǎo)致整個(gè)集群會(huì)有同時(shí)有兩個(gè) NameNode泼掠,這就是腦裂問題怔软。
當(dāng)出現(xiàn)ZKFC所在JVM因?yàn)樨?fù)載高或者Full GC時(shí)間長(zhǎng),這時(shí)候會(huì)導(dǎo)致Zookeeper客戶端與Zookeeper服務(wù)端之間的心跳不正常择镇,如果超過了session超時(shí)時(shí)間挡逼,Zookeeper服務(wù)端就會(huì)刪除/hadoop-ha/{dfs.nameservices}/ActiveStandbyElectorLock這個(gè)臨時(shí)節(jié)點(diǎn),這個(gè)刪除操作被立馬被standby NameNode綁定的ZKFC感知到腻豌,然后創(chuàng)建/hadoop-ha/{dfs.nameservices}/ActiveStandbyElectorLock臨時(shí)節(jié)點(diǎn)成功家坎,最終成為新的active NameNode節(jié)點(diǎn)。這種情況下一定的時(shí)間內(nèi)舊的active NameNode任然認(rèn)為自己是active主節(jié)點(diǎn)吝梅。這時(shí)候整個(gè)HDFS系統(tǒng)存在兩個(gè)active NameNode虱疏,產(chǎn)生了腦裂,這對(duì)強(qiáng)一致性的HDFS系統(tǒng)是不能容忍的苏携。
如何解決腦裂:
腦裂問題的解決方案是隔離(Fencing)做瞪,主要是在以下三處采用隔離措施:
第三方共享存儲(chǔ):任一時(shí)刻,只有一個(gè) NN 可以寫入右冻;
DataNode:需要保證只有一個(gè) NN 發(fā)出與管理數(shù)據(jù)副本有關(guān)的命令装蓬;
Client:需要保證同一時(shí)刻只有一個(gè) NN 能夠?qū)?Client 的請(qǐng)求發(fā)出正確的響應(yīng)。
關(guān)于這個(gè)問題目前解決方案的實(shí)現(xiàn)如下:
ActiveStandbyElector 為了實(shí)現(xiàn) fencing纱扭,會(huì)在成功創(chuàng)建 Zookeeper 節(jié)點(diǎn) hadoop-ha/${dfs.nameservices}/ActiveStandbyElectorLock 從而成為 Active NameNode 之后牍帚,創(chuàng)建另外一個(gè)路徑為 /hadoop-ha/${dfs.nameservices}/ActiveBreadCrumb 的持久節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)里面保存了這個(gè) Active NameNode 的地址信息跪但;
Active NameNode 的 ActiveStandbyElector 在正常的狀態(tài)下關(guān)閉 Zookeeper Session 的時(shí)候履羞,會(huì)一起刪除這個(gè)持久節(jié)點(diǎn);
但如果 ActiveStandbyElector 在異常的狀態(tài)下 Zookeeper Session 關(guān)閉 (比如前述的 Zookeeper 假死)屡久,假死導(dǎo)致 /hadoop-ha/${dfs.nameservices}/ActiveBreadCrumb 持久節(jié)點(diǎn)會(huì)保留下來忆首,后面當(dāng)另一個(gè) NameNode 選主成功之后,會(huì)注意到上一個(gè) Active NameNode 遺留下來的這個(gè)節(jié)點(diǎn)被环,從而會(huì)回調(diào) ZKFailoverController 的方法對(duì)舊的 Active NameNode 進(jìn)行 fencing糙及。
在進(jìn)行 fencing 的時(shí)候,會(huì)執(zhí)行以下的操作:
a筛欢、首先嘗試調(diào)用這個(gè)舊 Active NameNode 的 HAServiceProtocol服務(wù)的 transitionToStandby方法浸锨,看能不能把它轉(zhuǎn)換為Standby狀態(tài)唇聘。
b、如果 transitionToStandby 方法調(diào)用失敗柱搜,那么就執(zhí)行 Hadoop 配置文件之中預(yù)定義的隔離措施迟郎,Hadoop 目前主要提供兩種隔離措施:
sshfence:通過 SSH 登錄到目標(biāo)機(jī)器上,執(zhí)行命令 fuser 將對(duì)應(yīng)的進(jìn)程殺死聪蘸;
shellfence:執(zhí)行一個(gè)用戶自定義的 shell 腳本來將對(duì)應(yīng)的進(jìn)程隔離宪肖;
只有在成功地執(zhí)行完成 fencing 之后,選主成功的 ActiveStandbyElector 才會(huì)回調(diào) ZKFailoverController 的?becomeActive?方法將對(duì)應(yīng)的 NameNode 轉(zhuǎn)換為 Active 狀態(tài)健爬,開始對(duì)外提供服務(wù)控乾。
三.聯(lián)邦機(jī)制
Federation 的核心思想是將一個(gè)大的 namespace 劃分多個(gè)子 namespace,并且每個(gè) namespace 分別由單獨(dú)的 NameNode 負(fù)責(zé)娜遵,這些 NameNode 之間互相獨(dú)立蜕衡,不會(huì)影響,不需要做任何協(xié)調(diào)工作(其實(shí)跟拆集群有一些相似)设拟,集群的所有 DataNode 會(huì)被多個(gè) NameNode 共享(在聯(lián)邦機(jī)制中慨仿,所有nameNode和dataNode都是相同的clusterId爬立,所以dataNode才會(huì)被所有nameNode共享)苟呐。
其中,每個(gè)子 namespace 和 DataNode 之間會(huì)由數(shù)據(jù)塊管理層作為中介建立映射關(guān)系,數(shù)據(jù)塊管理層由若干數(shù)據(jù)塊池(Pool)構(gòu)成躲雅,每個(gè)數(shù)據(jù)塊(block)只會(huì)唯一屬于某個(gè)固定的數(shù)據(jù)塊池,而一個(gè)子 namespace 可以對(duì)應(yīng)多個(gè)數(shù)據(jù)塊池骡和。每個(gè) DataNode 需要向集群中所有的 NameNode 注冊(cè)相赁,且周期性地向所有 NameNode 發(fā)送心跳和塊報(bào)告,并執(zhí)行來自所有 NameNode 的命令慰于。一個(gè) block pool 由屬于同一個(gè) namespace 的數(shù)據(jù)塊組成钮科,每個(gè) DataNode 可能會(huì)存儲(chǔ)集群中所有 block pool 的數(shù)據(jù)塊;
多個(gè) NN 共用一個(gè)集群里的存儲(chǔ)資源婆赠,每個(gè) NN 都可以單獨(dú)對(duì)外提供服務(wù)绵脯。
每個(gè) NN 都會(huì)定義一個(gè)存儲(chǔ)池,有單獨(dú)的 id休里,每個(gè) DN 都為所有存儲(chǔ)池提供存儲(chǔ)蛆挫。
DN 會(huì)按照存儲(chǔ)池 id 向其對(duì)應(yīng)的 NN 匯報(bào)塊信息,同時(shí)妙黍,DN 會(huì)向所有 NN 匯報(bào)本地存儲(chǔ)可用資源情況
每個(gè) block pool 內(nèi)部自治悴侵,也就是說各自管理各自的 block,不會(huì)與其他 block pool 交流拭嫁,如果一個(gè) NameNode 掛掉了可免,不會(huì)影響其他 NameNode;
某個(gè) NameNode 上的 namespace 和它對(duì)應(yīng)的 block pool 一起被稱為 namespace volume抓于,它是管理的基本單位。當(dāng)一個(gè) NameNode/namespace 被刪除后浇借,其所有 DataNode 上對(duì)應(yīng)的 block pool 也會(huì)被刪除捉撮,當(dāng)集群升級(jí)時(shí),每個(gè) namespace volume 可以作為一個(gè)基本單元進(jìn)行升級(jí)妇垢。