這篇文章寫的很優(yōu)秀咬清,然后自己稍微整理了下旧烧。轉(zhuǎn)自:https://matt33.com/2018/07/15/hdfs-architecture-learn/
1、HDFS 1.0 的問題
在前面的介紹中夺谁,關(guān)于 HDFS1.0 的架構(gòu)匾鸥,首先都會看到 NameNode 的單點問題扫腺,這個在生產(chǎn)環(huán)境中是非常要命的問題笆环,早期的 HDFS 由于規(guī)模較小躁劣,有些問題就被隱藏了志膀,但自從進入了移動互聯(lián)網(wǎng)時代溉浙,很多公司都開始進入了 PB 級的大數(shù)據(jù)時代戳稽,HDFS 1.0的設(shè)計缺陷已經(jīng)無法滿足生產(chǎn)的需求,最致命的問題有以下兩點:
- NameNode 的單點問題颂郎,如果 NameNode 掛掉了,數(shù)據(jù)讀寫都會受到影響竭缝,HDFS 整體將變得不可用,這在生產(chǎn)環(huán)境中是不可接受的耿戚;
技術(shù)難點:如何保持主備NameNode的狀態(tài)同步,并讓Standby在Active掛掉后迅速提供服務(wù)皂股,NameNode啟動比較耗時呜呐,包括FSimage和Editlog(獲取file to block)洋机,處理所有DataNode第一次blockreport(獲取block to DataNode信息)绷旗,保持NN的狀態(tài)同步衔肢,需要這兩部信息同步膀懈。
- 水平擴展問題,隨著集群規(guī)模的擴大胳赌,1.0 時集群規(guī)模達到3000時疑苫,會導致整個集群管理的文件數(shù)目達到上限(因為 NameNode 要管理整個集群 block 元信息、數(shù)據(jù)目錄信息等)挺勿。
為了解決上面的兩個問題,Hadoop2.0 提供一套統(tǒng)一的解決方案:
- 1蚊丐、HA(High Availability 高可用方案):這個是為了解決 NameNode 單點問題;
- 2凛篙、NameNode Federation:是用來解決 HDFS 集群的線性擴展能力膀捷。
2、HDFS 2.0 的 HA 實現(xiàn)
關(guān)于 HDFS 高可用方案壶笼,非常推薦這篇文章:Hadoop NameNode 高可用 (High Availability) 實現(xiàn)解析,IBM 博客的質(zhì)量確實很高,這部分我這里也是主要根據(jù)這篇文章做一個總結(jié)坤候,這里會從問題的原因、如何解決的角度去總結(jié)徒河,并不會深入源碼的實現(xiàn)細節(jié),想有更深入了解還是推薦上面文章。
這里先看下 HDFS 高可用解決方案的架構(gòu)設(shè)計,如下圖(下圖來自上面的文章)所示:
這里與前面 1.0 的架構(gòu)已經(jīng)有很大變化,簡單介紹一下上面的組件:
- 1、
Active NameNode(ANN)
和Standby NameNode(SNN)
:兩臺 NameNode 形成互備,一臺處于 Active 狀態(tài)贬堵,為主 NameNode松忍,另外一臺處于 Standby 狀態(tài)宏所,為備 NameNode更扁,只有主 NameNode 才能對外提供讀寫服務(wù)溃列; - 2哄啄、
ZKFailoverController(主備切換控制器沪么,F(xiàn)C)
:ZKFailoverController 作為獨立的進程運行,對 NameNode 的主備切換進行總體控制州胳。ZKFailoverController 能及時檢測到 NameNode 的健康狀況碗硬,在主 NameNode 故障時借助 Zookeeper 實現(xiàn)自動的主備選舉和切換(當然 NameNode 目前也支持不依賴于 Zookeeper 的手動主備切換); - 3、Zookeeper 集群:為主備切換控制器提供主備選舉支持;
- 4、共享存儲系統(tǒng):共享存儲系統(tǒng)是實現(xiàn) NameNode 的高可用最為關(guān)鍵的部分搀罢,共享存儲系統(tǒng)保存了 NameNode 在運行過程中所產(chǎn)生的 HDFS 的元數(shù)據(jù)榔至。主 NameNode 和備 NameNode 通過共享存儲系統(tǒng)實現(xiàn)元數(shù)據(jù)同步抵赢。在進行主備切換的時候,新的主 NameNode 在確認元數(shù)據(jù)完全同步之后才能繼續(xù)對外提供服務(wù)唧取。
- 5铅鲤、DataNode 節(jié)點:因為主 NameNode 和備 NameNode 需要共享 HDFS 的數(shù)據(jù)塊和 DataNode 之間的映射關(guān)系,為了使故障切換能夠快速進行枫弟,DataNode 會同時向主 NameNode 和備 NameNode 上報數(shù)據(jù)塊的位置信息邢享。
3、FailoverController
FC 最初的目的是為了實現(xiàn) SNN 和 ANN 之間故障自動切換淡诗,F(xiàn)C 是獨立與 NN 之外的故障切換控制器驼仪,ZKFC 作為 NameNode 機器上一個獨立的進程啟動 掸犬,它啟動的時候會創(chuàng)建 HealthMonitor
和ActiveStandbyElector
這兩個主要的內(nèi)部組件袜漩,其中:
- HealthMonitor:主要負責檢測 NameNode 的健康狀態(tài)绪爸,如果檢測到 NameNode 的狀態(tài)發(fā)生變化,會回調(diào) ZKFailoverController 的相應(yīng)方法進行自動的主備選舉宙攻;
- ActiveStandbyElector:主要負責完成自動的主備選舉奠货,內(nèi)部封裝了 Zookeeper 的處理邏輯,一旦 Zookeeper 主備選舉完成座掘,會回調(diào) ZKFailoverController 的相應(yīng)方法來進行 NameNode 的主備狀態(tài)切換递惋。
4 、自動觸發(fā)主備選舉
NameNode 在選舉成功后溢陪,會在 zk 上創(chuàng)建了一個 /hadoop-ha/${dfs.nameservices}/ActiveStandbyElectorLock 節(jié)點萍虽,而沒有選舉成功的備 NameNode 會監(jiān)控這個節(jié)點,通過 Watcher 來監(jiān)聽這個節(jié)點的狀態(tài)變化事件形真,ZKFC 的 ActiveStandbyElector 主要關(guān)注這個節(jié)點的 NodeDeleted
事件(這部分實現(xiàn)跟 Kafka 中 Controller 的選舉一樣)杉编。
如果 Active NameNode 對應(yīng)的 HealthMonitor 檢測到 NameNode 的狀態(tài)異常時, ZKFailoverController 會主動刪除當前在 Zookeeper 上建立的臨時節(jié)點 /hadoop-ha/{dfs.nameservices}/ActiveStandbyElectorLock咆霜,這樣處于 Standby 狀態(tài)的 NameNode 的 ActiveStandbyElector 注冊的監(jiān)聽器就會收到這個節(jié)點的 NodeDeleted 事件邓馒。收到這個事件之后,會馬上再次進入到創(chuàng)建 /hadoop-ha/{dfs.nameservices}/ActiveStandbyElectorLock 節(jié)點的流程蛾坯,如果創(chuàng)建成功光酣,這個本來處于 Standby 狀態(tài)的 NameNode 就選舉為主 NameNode 并隨后開始切換為 Active 狀態(tài)。
當然脉课,如果是 Active 狀態(tài)的 NameNode 所在的機器整個宕掉的話救军,那么根據(jù) Zookeeper 的臨時節(jié)點特性,/hadoop-ha/${dfs.nameservices}/ActiveStandbyElectorLock 節(jié)點會自動被刪除倘零,從而也會自動進行一次主備切換唱遭。
5、HDFS 腦裂(split-brain)問題
在實際中视事,NameNode 可能會出現(xiàn)這種情況胆萧,NameNode 在垃圾回收(GC)時,可能會在長時間內(nèi)整個系統(tǒng)無響應(yīng)俐东,因此跌穗,也就無法向 zk 寫入心跳信息,這樣的話可能會導致臨時節(jié)點掉線虏辫,備 NameNode 會切換到 Active 狀態(tài)蚌吸,這種情況,可能會導致整個集群會有同時有兩個 NameNode砌庄,這就是腦裂問題羹唠。
腦裂問題的解決方案是隔離(Fencing)奕枢,主要是在以下三處采用隔離措施:
- 1、
第三方共享存儲
:任一時刻佩微,只有一個 NN 可以寫入缝彬; - 2、
DataNode
:需要保證只有一個 NN 發(fā)出與管理數(shù)據(jù)副本有關(guān)的刪除命令哺眯; - 3谷浅、
Client
:需要保證同一時刻只有一個 NN 能夠?qū)?Client 的請求發(fā)出正確的響應(yīng)。
關(guān)于這個問題目前解決方案的實現(xiàn)如下:
- ActiveStandbyElector 為了實現(xiàn) fencing奶卓,會在成功創(chuàng)建 Zookeeper 節(jié)點 hadoop-ha/{dfs.nameservices}/ActiveStandbyElectorLock 從而成為 Active NameNode 之后一疯,創(chuàng)建另外一個路徑為 /hadoop-ha/${dfs.nameservices}/ActiveBreadCrumb 的持久節(jié)點,這個節(jié)點里面保存了這個 Active NameNode 的地址信息夺姑;
- Active NameNode 的 ActiveStandbyElector 在正常的狀態(tài)下關(guān)閉 Zookeeper Session 的時候墩邀,會一起刪除這個持久節(jié)點;
- 但如果 ActiveStandbyElector 在異常的狀態(tài)下 Zookeeper Session 關(guān)閉 (比如前述的 Zookeeper 假死)盏浙,那么由于 /hadoop-ha/${dfs.nameservices}/ActiveBreadCrumb 是持久節(jié)點眉睹,會一直保留下來,后面當另一個 NameNode 選主成功之后只盹,會注意到上一個 Active NameNode 遺留下來的這個節(jié)點辣往,從而會回調(diào) ZKFailoverController 的方法對舊的 Active NameNode 進行 fencing。
在進行 fencing 的時候殖卑,會執(zhí)行以下的操作:
- 1站削、首先嘗試調(diào)用這個舊 Active NameNode 的 HAServiceProtocol RPC 接口的 transitionToStandby 方法,看能不能把它轉(zhuǎn)換為 Standby 狀態(tài)孵稽;
- 2许起、如果 transitionToStandby 方法調(diào)用失敗,那么就執(zhí)行 Hadoop 配置文件之中預定義的隔離措施菩鲜。
Hadoop 目前主要提供兩種隔離措施园细,通常會選擇第一種:
- 1、
sshfence
:通過 SSH 登錄到目標機器上接校,執(zhí)行命令 fuser 將對應(yīng)的進程殺死猛频; - 2、
shellfence
:執(zhí)行一個用戶自定義的 shell 腳本來將對應(yīng)的進程隔離蛛勉。
只有在成功地執(zhí)行完成 fencing 之后鹿寻,選主成功的 ActiveStandbyElector 才會回調(diào) ZKFailoverController 的 becomeActive 方法將對應(yīng)的 NameNode 轉(zhuǎn)換為 Active 狀態(tài),開始對外提供服務(wù)诽凌。
NameNode 選舉的實現(xiàn)機制與 Kafka 的 Controller 類似毡熏,那么 Kafka 是如何避免腦裂問題的呢?
- 1侣诵、Controller 給 Broker 發(fā)送的請求中痢法,都會攜帶 controller epoch 信息狱窘,如果 broker 發(fā)現(xiàn)當前請求的 epoch 小于緩存中的值,那么就證明這是來自舊 Controller 的請求财搁,就會決絕這個請求蘸炸,正常情況下是沒什么問題的;
- 2妇拯、但是異常情況下呢幻馁?如果 Broker 先收到異常 Controller 的請求進行處理呢?現(xiàn)在看 Kafka 在這一部分并沒有適合的方案越锈;
- 3、正常情況下膘滨,Kafka 新的 Controller 選舉出來之后甘凭,Controller 會向全局所有 broker 發(fā)送一個 metadata 請求,這樣全局所有 Broker 都可以知道當前最新的 controller epoch火邓,但是并不能保證可以完全避免上面這個問題丹弱,還是有出現(xiàn)這個問題的幾率的,只不過非常小铲咨,而且即使出現(xiàn)了由于 Kafka 的高可靠架構(gòu)躲胳,影響也非常有限,至少從目前看纤勒,這個問題并不是嚴重的問題坯苹。
6、第三方存儲(共享存儲)
上述 HA 方案還有一個明顯缺點摇天,那就是第三方存儲節(jié)點有可能失效粹湃,之前有很多共享存儲的實現(xiàn)方案,目前社區(qū)已經(jīng)把由 Clouderea 公司實現(xiàn)的基于 QJM 的方案合并到 HDFS 的 trunk 之中并且作為默認的共享存儲實現(xiàn)泉坐,本部分只針對基于 QJM 的共享存儲方案的內(nèi)部實現(xiàn)原理進行分析为鳄。
QJM(Quorum Journal Manager)
本質(zhì)上是利用 Paxos 協(xié)議來實現(xiàn)的,QJM 在 2F+1 個 JournalNode 上存儲 NN 的 editlog嗦锐,每次寫入操作都通過 Paxos 保證寫入的一致性祖今,它最多可以允許有 F 個 JournalNode 節(jié)點同時故障挨务,其實現(xiàn)如下(圖片來自:Hadoop NameNode 高可用 (High Availability) 實現(xiàn)解析 ):
基于 QJM 的共享存儲的數(shù)據(jù)同步機制
Active NameNode 首先把 EditLog 提交到 JournalNode 集群,然后 Standby NameNode 再從 JournalNode 集群定時同步 EditLog偏形。
還有一點需要注意的是,在 2.0 中不再有 SNN 這個角色了液南,NameNode 在啟動后壳猜,會先加載 FSImage 文件和共享目錄上的 EditLog Segment 文件滑凉,之后 NameNode 會啟動 EditLogTailer 線程和 StandbyCheckpointer 線程统扳,正式進入 Standby 模式喘帚,其中:
- 1、
EditLogTailer
線程的作用是定時從 JournalNode 集群上同步 EditLog咒钟; - 2吹由、
StandbyCheckpointer
線程的作用其實是為了替代 Hadoop 1.x 版本之中的 Secondary NameNode 的功能,StandbyCheckpointer 線程會在 Standby NameNode 節(jié)點上定期進行 Checkpoint朱嘴,將 Checkpoint 之后的 FSImage 文件上傳到 Active NameNode 節(jié)點倾鲫。
7、HDFS 2.0 Federation 實現(xiàn)
在 1.0 中萍嬉,HDFS 的架構(gòu)設(shè)計有以下缺點:
- 1乌昔、namespace 擴展性差:在單一的 NN 情況下,因為所有 namespace 數(shù)據(jù)都需要加載到內(nèi)存壤追,所以物理機內(nèi)存的大小限制了整個 HDFS 能夠容納文件的最大個數(shù)(namespace 指的是 HDFS 中樹形目錄和文件結(jié)構(gòu)以及文件對應(yīng)的 block 信息)磕道;
- 2、性能可擴展性差:由于所有請求都需要經(jīng)過 NN行冰,單一 NN 導致所有請求都由一臺機器進行處理溺蕉,很容易達到單臺機器的吞吐;
- 3悼做、隔離性差:多租戶的情況下疯特,單一 NN 的架構(gòu)無法在租戶間進行隔離,會造成不可避免的相互影響肛走。
而 Federation 的設(shè)計就是為了解決這些問題漓雅,采用 Federation 的最主要原因是設(shè)計實現(xiàn)簡單,而且還能解決問題羹与。
8故硅、Federation 架構(gòu)
Federation 的架構(gòu)設(shè)計如下圖所示(圖片來自 HDFS Federation):
Federation 的核心設(shè)計思想
Federation
的核心思想是將一個大的 namespace 劃分多個子 namespace,并且每個 namespace 分別由單獨的 NameNode 負責纵搁,這些 NameNode 之間互相獨立吃衅,不會影響,不需要做任何協(xié)調(diào)工作(其實跟拆集群有一些相似)腾誉,集群的所有 DataNode 會被多個 NameNode 共享徘层。
其中,每個子 namespace 和 DataNode 之間會由數(shù)據(jù)塊管理層作為中介建立映射關(guān)系利职,數(shù)據(jù)塊管理層由若干數(shù)據(jù)塊池(Pool)構(gòu)成趣效,每個數(shù)據(jù)塊只會唯一屬于某個固定的數(shù)據(jù)塊池,而一個子 namespace 可以對應(yīng)多個數(shù)據(jù)塊池猪贪。每個 DataNode 需要向集群中所有的 NameNode 注冊跷敬,且周期性地向所有 NameNode 發(fā)送心跳和塊報告,并執(zhí)行來自所有 NameNode 的命令热押。
- 一個 block pool 由屬于同一個 namespace 的數(shù)據(jù)塊組成西傀,每個 DataNode 可能會存儲集群中所有 block pool 的數(shù)據(jù)塊斤寇;
- 每個 block pool 內(nèi)部自治,也就是說各自管理各自的 block拥褂,不會與其他 block pool 交流娘锁,如果一個 NameNode 掛掉了,不會影響其他 NameNode;
- 某個 NameNode 上的 namespace 和它對應(yīng)的 block pool 一起被稱為 namespace volume饺鹃,它是管理的基本單位莫秆。當一個 NameNode/namespace 被刪除后,其所有 DataNode 上對應(yīng)的 block pool 也會被刪除悔详,當集群升級時镊屎,每個 namespace volume 可以作為一個基本單元進行升級。
到這里伟端,基本對 HDFS 這部分總結(jié)完了杯道,雖然文章的內(nèi)容基本都來自下面的參考資料,但是自己在總結(jié)的過程中责蝠,也對 HDFS 的基本架構(gòu)有一定的了解,后續(xù)結(jié)合公司 HDFS 團隊的 CaseStudy 深入學習這部分的內(nèi)容萎庭,工作中霜医,也慢慢感覺到分布式系統(tǒng),很多的設(shè)計實現(xiàn)與問題解決方案都很類似驳规,只不過因為面對業(yè)務(wù)場景的不同而采用了不同的實現(xiàn)肴敛。
9、參考資料
- HDFS Architecture;
- HDFS 寫文件過程分析;
- HDFS Router-based Federation吗购;
- HDFS High Availability Using the Quorum Journal Manager医男;
- HDFS Commands Guide;
- Hadoop NameNode 高可用 (High Availability) 實現(xiàn)解析
- HDFS Federation捻勉;
- HDFS Federation設(shè)計動機與基本原理镀梭;
- 《大數(shù)據(jù)日知錄:架構(gòu)與算法》;
- HDFS NameNode重啟優(yōu)化踱启;
- HDFS Federation在美團點評的應(yīng)用與改進报账。