HDFS單點(diǎn)故障和線性擴(kuò)展問(wèn)題

這篇文章寫(xiě)的很優(yōu)秀,然后自己稍微整理了下。轉(zhuǎn)自:https://matt33.com/2018/07/15/hdfs-architecture-learn/

1、HDFS 1.0 的問(wèn)題

在前面的介紹中,關(guān)于 HDFS1.0 的架構(gòu),首先都會(huì)看到 NameNode 的單點(diǎn)問(wèn)題,這個(gè)在生產(chǎn)環(huán)境中是非常要命的問(wèn)題,早期的 HDFS 由于規(guī)模較小,有些問(wèn)題就被隱藏了,但自從進(jìn)入了移動(dòng)互聯(lián)網(wǎng)時(shí)代,很多公司都開(kāi)始進(jìn)入了 PB 級(jí)的大數(shù)據(jù)時(shí)代,HDFS 1.0的設(shè)計(jì)缺陷已經(jīng)無(wú)法滿(mǎn)足生產(chǎn)的需求,最致命的問(wèn)題有以下兩點(diǎn):

  • NameNode 的單點(diǎn)問(wèn)題,如果 NameNode 掛掉了,數(shù)據(jù)讀寫(xiě)都會(huì)受到影響,HDFS 整體將變得不可用,這在生產(chǎn)環(huán)境中是不可接受的;

技術(shù)難點(diǎn):如何保持主備N(xiāo)ameNode的狀態(tài)同步,并讓Standby在Active掛掉后迅速提供服務(wù),NameNode啟動(dòng)比較耗時(shí),包括FSimage和Editlog(獲取file to block),處理所有DataNode第一次blockreport(獲取block to DataNode信息),保持NN的狀態(tài)同步,需要這兩部信息同步。

  • 水平擴(kuò)展問(wèn)題,隨著集群規(guī)模的擴(kuò)大,1.0 時(shí)集群規(guī)模達(dá)到3000時(shí),會(huì)導(dǎo)致整個(gè)集群管理的文件數(shù)目達(dá)到上限(因?yàn)?NameNode 要管理整個(gè)集群 block 元信息、數(shù)據(jù)目錄信息等)。

為了解決上面的兩個(gè)問(wèn)題,Hadoop2.0 提供一套統(tǒng)一的解決方案:

  • 1、HA(High Availability 高可用方案):這個(gè)是為了解決 NameNode 單點(diǎn)問(wèn)題;
  • 2、NameNode Federation:是用來(lái)解決 HDFS 集群的線性擴(kuò)展能力。

2、HDFS 2.0 的 HA 實(shí)現(xiàn)

關(guān)于 HDFS 高可用方案,非常推薦這篇文章:Hadoop NameNode 高可用 (High Availability) 實(shí)現(xiàn)解析,IBM 博客的質(zhì)量確實(shí)很高,這部分我這里也是主要根據(jù)這篇文章做一個(gè)總結(jié),這里會(huì)從問(wèn)題的原因、如何解決的角度去總結(jié),并不會(huì)深入源碼的實(shí)現(xiàn)細(xì)節(jié),想有更深入了解還是推薦上面文章。

這里先看下 HDFS 高可用解決方案的架構(gòu)設(shè)計(jì),如下圖(下圖來(lái)自上面的文章)所示:

754a25160047149592b9d6b979a8f6bd

這里與前面 1.0 的架構(gòu)已經(jīng)有很大變化,簡(jiǎn)單介紹一下上面的組件:

  • 1、Active NameNode(ANN)Standby NameNode(SNN):兩臺(tái) NameNode 形成互備,一臺(tái)處于 Active 狀態(tài),為主 NameNode,另外一臺(tái)處于 Standby 狀態(tài),為備 NameNode,只有主 NameNode 才能對(duì)外提供讀寫(xiě)服務(wù);
  • 2、ZKFailoverController(主備切換控制器,F(xiàn)C):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 目前也支持不依賴(lài)于 Zookeeper 的手動(dòng)主備切換);
  • 3、Zookeeper 集群:為主備切換控制器提供主備選舉支持;
  • 4、共享存儲(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ù)。
  • 5、DataNode 節(jié)點(diǎn):因?yàn)橹?NameNode 和備 NameNode 需要共享 HDFS 的數(shù)據(jù)塊和 DataNode 之間的映射關(guān)系,為了使故障切換能夠快速進(jìn)行,DataNode 會(huì)同時(shí)向主 NameNode 和備 NameNode 上報(bào)數(shù)據(jù)塊的位置信息。

3、FailoverController

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)建 HealthMonitorActiveStandbyElector這兩個(gè)主要的內(nèi)部組件,其中:

  1. HealthMonitor:主要負(fù)責(zé)檢測(cè) NameNode 的健康狀態(tài),如果檢測(cè)到 NameNode 的狀態(tài)發(fā)生變化,會(huì)回調(diào) ZKFailoverController 的相應(yīng)方法進(jìn)行自動(dòng)的主備選舉;
  2. ActiveStandbyElector:主要負(fù)責(zé)完成自動(dòng)的主備選舉,內(nèi)部封裝了 Zookeeper 的處理邏輯,一旦 Zookeeper 主備選舉完成,會(huì)回調(diào) ZKFailoverController 的相應(yīng)方法來(lái)進(jìn)行 NameNode 的主備狀態(tài)切換。
img

4 、自動(dòng)觸發(fā)主備選舉

NameNode 在選舉成功后,會(huì)在 zk 上創(chuàng)建了一個(gè) /hadoop-ha/${dfs.nameservices}/ActiveStandbyElectorLock 節(jié)點(diǎn),而沒(méi)有選舉成功的備 NameNode 會(huì)監(jiān)控這個(gè)節(jié)點(diǎn),通過(guò) Watcher 來(lái)監(jiān)聽(tīng)這個(gè)節(jié)點(diǎn)的狀態(tài)變化事件,ZKFC 的 ActiveStandbyElector 主要關(guān)注這個(gè)節(jié)點(diǎn)的 NodeDeleted 事件(這部分實(shí)現(xiàn)跟 Kafka 中 Controller 的選舉一樣)。

如果 Active NameNode 對(duì)應(yīng)的 HealthMonitor 檢測(cè)到 NameNode 的狀態(tài)異常時(shí), ZKFailoverController 會(huì)主動(dòng)刪除當(dāng)前在 Zookeeper 上建立的臨時(shí)節(jié)點(diǎn) /hadoop-ha/{dfs.nameservices}/ActiveStandbyElectorLock,這樣處于 Standby 狀態(tài)的 NameNode 的 ActiveStandbyElector 注冊(cè)的監(jiān)聽(tīng)器就會(huì)收到這個(gè)節(jié)點(diǎn)的 NodeDeleted 事件。收到這個(gè)事件之后,會(huì)馬上再次進(jìn)入到創(chuàng)建 /hadoop-ha/{dfs.nameservices}/ActiveStandbyElectorLock 節(jié)點(diǎn)的流程,如果創(chuàng)建成功,這個(gè)本來(lái)處于 Standby 狀態(tài)的 NameNode 就選舉為主 NameNode 并隨后開(kāi)始切換為 Active 狀態(tài)。

當(dāng)然,如果是 Active 狀態(tài)的 NameNode 所在的機(jī)器整個(gè)宕掉的話,那么根據(jù) Zookeeper 的臨時(shí)節(jié)點(diǎn)特性,/hadoop-ha/${dfs.nameservices}/ActiveStandbyElectorLock 節(jié)點(diǎn)會(huì)自動(dòng)被刪除,從而也會(huì)自動(dòng)進(jìn)行一次主備切換。

5、HDFS 腦裂(split-brain)問(wèn)題

在實(shí)際中,NameNode 可能會(huì)出現(xiàn)這種情況,NameNode 在垃圾回收(GC)時(shí),可能會(huì)在長(zhǎng)時(shí)間內(nèi)整個(gè)系統(tǒng)無(wú)響應(yīng),因此,也就無(wú)法向 zk 寫(xiě)入心跳信息,這樣的話可能會(huì)導(dǎo)致臨時(shí)節(jié)點(diǎn)掉線,備 NameNode 會(huì)切換到 Active 狀態(tài),這種情況,可能會(huì)導(dǎo)致整個(gè)集群會(huì)有同時(shí)有兩個(gè) NameNode,這就是腦裂問(wèn)題。

腦裂問(wèn)題的解決方案是隔離(Fencing),主要是在以下三處采用隔離措施:

  • 1、第三方共享存儲(chǔ):任一時(shí)刻,只有一個(gè) NN 可以寫(xiě)入;
  • 2、DataNode:需要保證只有一個(gè) NN 發(fā)出與管理數(shù)據(jù)副本有關(guān)的刪除命令;
  • 3、Client:需要保證同一時(shí)刻只有一個(gè) NN 能夠?qū)?Client 的請(qǐng)求發(fā)出正確的響應(yīng)。

關(guān)于這個(gè)問(wèn)題目前解決方案的實(shí)現(xiàn)如下:

  1. 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 的地址信息;
  2. Active NameNode 的 ActiveStandbyElector 在正常的狀態(tài)下關(guān)閉 Zookeeper Session 的時(shí)候,會(huì)一起刪除這個(gè)持久節(jié)點(diǎn);
  3. 但如果 ActiveStandbyElector 在異常的狀態(tài)下 Zookeeper Session 關(guān)閉 (比如前述的 Zookeeper 假死),那么由于 /hadoop-ha/${dfs.nameservices}/ActiveBreadCrumb 是持久節(jié)點(diǎn),會(huì)一直保留下來(lái),后面當(dāng)另一個(gè) NameNode 選主成功之后,會(huì)注意到上一個(gè) Active NameNode 遺留下來(lái)的這個(gè)節(jié)點(diǎn),從而會(huì)回調(diào) ZKFailoverController 的方法對(duì)舊的 Active NameNode 進(jìn)行 fencing。

在進(jìn)行 fencing 的時(shí)候,會(huì)執(zhí)行以下的操作:

  • 1、首先嘗試調(diào)用這個(gè)舊 Active NameNode 的 HAServiceProtocol RPC 接口的 transitionToStandby 方法,看能不能把它轉(zhuǎn)換為 Standby 狀態(tài);
  • 2、如果 transitionToStandby 方法調(diào)用失敗,那么就執(zhí)行 Hadoop 配置文件之中預(yù)定義的隔離措施。

Hadoop 目前主要提供兩種隔離措施,通常會(huì)選擇第一種:

  • 1、sshfence:通過(guò) SSH 登錄到目標(biāo)機(jī)器上,執(zhí)行命令 fuser 將對(duì)應(yīng)的進(jìn)程殺死;
  • 2、shellfence:執(zhí)行一個(gè)用戶(hù)自定義的 shell 腳本來(lái)將對(duì)應(yīng)的進(jìn)程隔離。

只有在成功地執(zhí)行完成 fencing 之后,選主成功的 ActiveStandbyElector 才會(huì)回調(diào) ZKFailoverController 的 becomeActive 方法將對(duì)應(yīng)的 NameNode 轉(zhuǎn)換為 Active 狀態(tài),開(kāi)始對(duì)外提供服務(wù)。

NameNode 選舉的實(shí)現(xiàn)機(jī)制與 Kafka 的 Controller 類(lèi)似,那么 Kafka 是如何避免腦裂問(wèn)題的呢?

  • 1、Controller 給 Broker 發(fā)送的請(qǐng)求中,都會(huì)攜帶 controller epoch 信息,如果 broker 發(fā)現(xiàn)當(dāng)前請(qǐng)求的 epoch 小于緩存中的值,那么就證明這是來(lái)自舊 Controller 的請(qǐng)求,就會(huì)決絕這個(gè)請(qǐng)求,正常情況下是沒(méi)什么問(wèn)題的;
  • 2、但是異常情況下呢?如果 Broker 先收到異常 Controller 的請(qǐng)求進(jìn)行處理呢?現(xiàn)在看 Kafka 在這一部分并沒(méi)有適合的方案;
  • 3、正常情況下,Kafka 新的 Controller 選舉出來(lái)之后,Controller 會(huì)向全局所有 broker 發(fā)送一個(gè) metadata 請(qǐng)求,這樣全局所有 Broker 都可以知道當(dāng)前最新的 controller epoch,但是并不能保證可以完全避免上面這個(gè)問(wèn)題,還是有出現(xiàn)這個(gè)問(wèn)題的幾率的,只不過(guò)非常小,而且即使出現(xiàn)了由于 Kafka 的高可靠架構(gòu),影響也非常有限,至少?gòu)哪壳翱矗@個(gè)問(wèn)題并不是嚴(yán)重的問(wèn)題。

6、第三方存儲(chǔ)(共享存儲(chǔ))

上述 HA 方案還有一個(gè)明顯缺點(diǎn),那就是第三方存儲(chǔ)節(jié)點(diǎn)有可能失效,之前有很多共享存儲(chǔ)的實(shí)現(xiàn)方案,目前社區(qū)已經(jīng)把由 Clouderea 公司實(shí)現(xiàn)的基于 QJM 的方案合并到 HDFS 的 trunk 之中并且作為默認(rèn)的共享存儲(chǔ)實(shí)現(xiàn),本部分只針對(duì)基于 QJM 的共享存儲(chǔ)方案的內(nèi)部實(shí)現(xiàn)原理進(jìn)行分析。

QJM(Quorum Journal Manager)本質(zhì)上是利用 Paxos 協(xié)議來(lái)實(shí)現(xiàn)的,QJM 在 2F+1 個(gè) JournalNode 上存儲(chǔ) NN 的 editlog,每次寫(xiě)入操作都通過(guò) Paxos 保證寫(xiě)入的一致性,它最多可以允許有 F 個(gè) JournalNode 節(jié)點(diǎn)同時(shí)故障,其實(shí)現(xiàn)如下(圖片來(lái)自:Hadoop NameNode 高可用 (High Availability) 實(shí)現(xiàn)解析 ):

image-20191109225330735

基于 QJM 的共享存儲(chǔ)的數(shù)據(jù)同步機(jī)制

Active NameNode 首先把 EditLog 提交到 JournalNode 集群,然后 Standby NameNode 再?gòu)?JournalNode 集群定時(shí)同步 EditLog。

還有一點(diǎn)需要注意的是,在 2.0 中不再有 SNN 這個(gè)角色了,NameNode 在啟動(dòng)后,會(huì)先加載 FSImage 文件和共享目錄上的 EditLog Segment 文件,之后 NameNode 會(huì)啟動(dòng) EditLogTailer 線程和 StandbyCheckpointer 線程,正式進(jìn)入 Standby 模式,其中:

  • 1、EditLogTailer 線程的作用是定時(shí)從 JournalNode 集群上同步 EditLog;
  • 2、StandbyCheckpointer 線程的作用其實(shí)是為了替代 Hadoop 1.x 版本之中的 Secondary NameNode 的功能,StandbyCheckpointer 線程會(huì)在 Standby NameNode 節(jié)點(diǎn)上定期進(jìn)行 Checkpoint,將 Checkpoint 之后的 FSImage 文件上傳到 Active NameNode 節(jié)點(diǎn)。

7、HDFS 2.0 Federation 實(shí)現(xiàn)

在 1.0 中,HDFS 的架構(gòu)設(shè)計(jì)有以下缺點(diǎn):

  • 1、namespace 擴(kuò)展性差:在單一的 NN 情況下,因?yàn)樗?namespace 數(shù)據(jù)都需要加載到內(nèi)存,所以物理機(jī)內(nèi)存的大小限制了整個(gè) HDFS 能夠容納文件的最大個(gè)數(shù)(namespace 指的是 HDFS 中樹(shù)形目錄和文件結(jié)構(gòu)以及文件對(duì)應(yīng)的 block 信息);
  • 2、性能可擴(kuò)展性差:由于所有請(qǐng)求都需要經(jīng)過(guò) NN,單一 NN 導(dǎo)致所有請(qǐng)求都由一臺(tái)機(jī)器進(jìn)行處理,很容易達(dá)到單臺(tái)機(jī)器的吞吐;
  • 3、隔離性差:多租戶(hù)的情況下,單一 NN 的架構(gòu)無(wú)法在租戶(hù)間進(jìn)行隔離,會(huì)造成不可避免的相互影響。

而 Federation 的設(shè)計(jì)就是為了解決這些問(wèn)題,采用 Federation 的最主要原因是設(shè)計(jì)實(shí)現(xiàn)簡(jiǎn)單,而且還能解決問(wèn)題。

8、Federation 架構(gòu)

Federation 的架構(gòu)設(shè)計(jì)如下圖所示(圖片來(lái)自 HDFS Federation):

image-20191109225426086

Federation 的核心設(shè)計(jì)思想

Federation的核心思想是將一個(gè)大的 namespace 劃分多個(gè)子 namespace,并且每個(gè) namespace 分別由單獨(dú)的 NameNode 負(fù)責(zé),這些 NameNode 之間互相獨(dú)立,不會(huì)影響,不需要做任何協(xié)調(diào)工作(其實(shí)跟拆集群有一些相似),集群的所有 DataNode 會(huì)被多個(gè) NameNode 共享。

其中,每個(gè)子 namespace 和 DataNode 之間會(huì)由數(shù)據(jù)塊管理層作為中介建立映射關(guān)系,數(shù)據(jù)塊管理層由若干數(shù)據(jù)塊池(Pool)構(gòu)成,每個(gè)數(shù)據(jù)塊只會(huì)唯一屬于某個(gè)固定的數(shù)據(jù)塊池,而一個(gè)子 namespace 可以對(duì)應(yīng)多個(gè)數(shù)據(jù)塊池。每個(gè) DataNode 需要向集群中所有的 NameNode 注冊(cè),且周期性地向所有 NameNode 發(fā)送心跳和塊報(bào)告,并執(zhí)行來(lái)自所有 NameNode 的命令。

  • 一個(gè) block pool 由屬于同一個(gè) namespace 的數(shù)據(jù)塊組成,每個(gè) DataNode 可能會(huì)存儲(chǔ)集群中所有 block pool 的數(shù)據(jù)塊;
  • 每個(gè) block pool 內(nèi)部自治,也就是說(shuō)各自管理各自的 block,不會(huì)與其他 block pool 交流,如果一個(gè) NameNode 掛掉了,不會(huì)影響其他 NameNode;
  • 某個(gè) NameNode 上的 namespace 和它對(duì)應(yīng)的 block pool 一起被稱(chēng)為 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í)。

到這里,基本對(duì) HDFS 這部分總結(jié)完了,雖然文章的內(nèi)容基本都來(lái)自下面的參考資料,但是自己在總結(jié)的過(guò)程中,也對(duì) HDFS 的基本架構(gòu)有一定的了解,后續(xù)結(jié)合公司 HDFS 團(tuán)隊(duì)的 CaseStudy 深入學(xué)習(xí)這部分的內(nèi)容,工作中,也慢慢感覺(jué)到分布式系統(tǒng),很多的設(shè)計(jì)實(shí)現(xiàn)與問(wèn)題解決方案都很類(lèi)似,只不過(guò)因?yàn)槊鎸?duì)業(yè)務(wù)場(chǎng)景的不同而采用了不同的實(shí)現(xiàn)。

9、參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容