[TOC]
本文嘗試說明下面三個問題
- HDFS 如何實現(xiàn)有狀態(tài)的高可用架構(gòu)
- HDFS 如何解決單機(jī)內(nèi)存受限問題
- HDFS 支持億級流量的密碼
- SecondaryNameNode 作用
1. HDFS 如何實現(xiàn)有狀態(tài)的高可用架構(gòu)
1.1 HDFS 架構(gòu)演進(jìn)之路
Hadoop 大版本有三個,Hadoop1、hadoop2、Hadoop3,對應(yīng)的HDFS 也有三個版本 HDFS1、HDFS2、HDFS3,本文會介紹 三個版本之間的架構(gòu)區(qū)別

1.2 HDFS1 架構(gòu)
HDFS 是一個分布式的文件系統(tǒng), 它是一個主從式的架構(gòu),其核心組件就是 NameNode(主節(jié)點,一個) 和 DataNode(從節(jié)點,多個)。
Namenode 主要是接收客戶端的請求和負(fù)責(zé)元數(shù)據(jù)管理,而 Datanode 主要就是負(fù)責(zé)存儲數(shù)據(jù)。Datanode 中存儲的數(shù)據(jù)都是一個個的塊,每個塊大小默認(rèn) 64M
具體使用一個客戶端上傳數(shù)據(jù)的示例來說明:
- HDFS 會把用戶上傳的文件切分成很多個 block,默認(rèn) 每個 block 大小是64M,
- 然后把這些 block 存儲在不同的 datanode 上,并且為每個 block 生成 3 個副本。
- 而每個 block 存在哪個 datanode上以及哪些 block 屬于一個文件這些信息都存儲在 Namanode 上,這些數(shù)據(jù)就是元數(shù)據(jù)
- Namanode 為了快速響應(yīng)用戶的請求,還會把這些元數(shù)據(jù)放到內(nèi)存中。
下面是一個簡單的 HDFS1 的架構(gòu)圖

1.3 HDFS2 架構(gòu)-實現(xiàn)有狀態(tài)的高可用架構(gòu)
雖然 HDFS1 解決了分布式存儲的問題,但是他的設(shè)計還是有一些缺陷,比如:
- 單點問題:因為 HDFS1 中只有一個 Namenode ,而所有的元數(shù)據(jù)信息都存儲在 Namenode 上,而一旦 Namenode 出現(xiàn)問題,所有的元數(shù)據(jù)就會丟失,而整個集群也就無法使用了
- 內(nèi)存受限問題:Namenode 為了快速響應(yīng)用戶的請求,會把所有元數(shù)據(jù)信息放到內(nèi)存中,隨著時間的推移,元數(shù)據(jù)信息增多,必然會撐爆內(nèi)存
基于這個兩個問題,HDFS2 誕生了,HDFS2 使用 HA 解決單點問題,使用 聯(lián)邦 解決內(nèi)存受限問題。
1.3.1 HDFS2 架構(gòu)-實現(xiàn)有狀態(tài)的高可用架構(gòu)
其實解決單點的問題,最直接的辦法就是在引入一個主節(jié)點(Namenode)唄。只要有兩個 Namenode,并且兩個Namenode的數(shù)據(jù)一致,當(dāng)其中一個壞掉時,使用另一個替換就可以了。其實HDFS2就是這么解決的。

HDFS2 又引入了一個 Namenode 并且給 Namenode 增加了狀態(tài),一個是 Active 狀態(tài)的,一個 Standby 狀態(tài)的,工作中由 Active 的 Namenode 負(fù)責(zé)接受用戶的操作請求,當(dāng) Active 的 Namenode 異常時,Standby 狀態(tài)的 Namenode 會切換狀態(tài)變?yōu)?Active 狀態(tài)。
但是這樣就會引入另外幾個問題:
- 一個是 Namenode 間的數(shù)據(jù)同步
- 一個是 Namenode 間的狀態(tài)自動切換
下面具體講解下,HDFS2 如何解決這兩個問題:
1.3.2 Namenode 間的數(shù)據(jù)同步
兩個 Namenode 要能達(dá)到切換的條件,必然是兩個 Namenode 的元數(shù)據(jù)要一直,那么如何保證兩個 Namenode 的元數(shù)據(jù)一致呢。HDFS 引入了 JournalNode 集群(類似zookeeper),該集群能保證數(shù)據(jù)的一致性。
在工作中, Active 的 Namenode 會向 JournalNode 同步新的元數(shù)據(jù)信息,而 Standby 的 Namenode 回讀 JournalNode 的元數(shù)據(jù)信息。一旦 Active 的 Namenode 出現(xiàn)異常,Standby 的 Namenode 會隨時切換為 Active。
1.3.3 Namenode 間的狀態(tài)自動切換
那么 Standby 的 Namenode 如何切換 Active 呢?HDFS 又引入了 zookeeper 集群,并且為每個 Namenode 增加了一個 zkfc 的服務(wù)。
zkfc 會定時監(jiān)控 Namenode 的狀態(tài),一旦 Namenode 狀態(tài)異常就會退出 zk的選舉列表。
HDFS2 具體的架構(gòu)圖如下:

提示:
- JournalNode 集群多少臺合適?
JournalNode 在實際工作中的壓力很小,一般 200 臺以上使用 3 臺 Journalnode 足夠了,200臺以上使用5臺基本都解決了 - JournalNode 集群是否可以使用 zookeeper 替代
其實是可以的,當(dāng)時這個具體要自己該源碼去實現(xiàn)
2. HDFS 如何解決單機(jī)內(nèi)存受限問題
其實解決內(nèi)存受限跟解決單點的思路類似,既然一臺主機(jī)不行就引入多臺

乍一看圖跟 HA 的第一個圖是一樣的,但是實現(xiàn)不同,HA里的兩個 Namenode 數(shù)據(jù)是要一致的,而這里的 Namenode 數(shù)據(jù)必須是不一樣的 (雖然圖上看不出區(qū)別),否則就沒有解決內(nèi)存受限的問題。這個就是 Namenode 的聯(lián)邦。
那 Namenode HA + 聯(lián)邦 后的架構(gòu)圖就如下:

可以看到我們需要為 聯(lián)邦 內(nèi)的每個 Namenode 提供 HA.
但這樣就會又引入一個問題,就是用戶訪問數(shù)據(jù)的時候到底應(yīng)該訪問哪個 Namenode 呢?
- 其實這個就類似數(shù)據(jù)庫的分庫分表一樣,需要提供一個路由的方案來解決訪問的問題,這個路由 Hadoop 并沒有提供,需要自己封裝。
- 或者可以 分業(yè)務(wù)存儲,比如 A 業(yè)務(wù)都存儲到 Namenode1 ,B 業(yè)務(wù)都使用 Namenode2,這樣就簡單解決了。
提示:
- 一般沒有必要的話,不建議使用聯(lián)邦(規(guī)模 1萬臺以下的集群)
3. HDFS 支持億級流量的密碼
3.1 HDFS 支持的億級流量具體什么?
這里所屬的支持億級流量具體是指客戶端的請求,因為 Namenode 管理元數(shù)據(jù),所有任務(wù)在執(zhí)行的時候都要請求 Namenode 的元數(shù)據(jù),而一旦任務(wù)多了這個請求量還是很可觀的。因為像大的企業(yè)上動不動就幾十萬,甚至上百萬的任務(wù),每個任務(wù)再有幾十個請求,那每天幾千萬的訪問量還是有的。
所以 Namenode 必須可以應(yīng)對 億級 的元數(shù)據(jù)請求,為了應(yīng)對這么大流量的訪問所以 Namenode 才把所有的元數(shù)據(jù)信息都放到內(nèi)存中了。但是又為了數(shù)據(jù)安全,Namenode 又會把 元數(shù)據(jù)信息放到磁盤上,且為了 HA 元數(shù)據(jù)還得寫到 JournalNode 集群中。
那問題就來了,如果元數(shù)據(jù)只內(nèi)存中,當(dāng)然能夠支持億級的請求,但是又要寫磁盤,又要寫 JournalNod ,Namenode 如何解決的呢?其實 Namenode 在管理元數(shù)據(jù)的時候,使用了兩個方法來解決此問題:
那就是 雙緩沖和分端加鎖
3.2 雙緩沖
雙緩沖其實就是兩塊內(nèi)存(代碼里其實就是兩個list)

Namenode 在接收客戶端的元數(shù)據(jù)操作請求時,是先把數(shù)據(jù)寫入
內(nèi)存1中,當(dāng)內(nèi)存1中的數(shù)據(jù)寫到一定程度的時候,把內(nèi)存1 與內(nèi)存2交換(這里是指針交換,不是內(nèi)存的copy),然后把交換后的內(nèi)存刷新到磁盤或者Journalnode中。
具體的實現(xiàn)大概如圖:

3.3 分段加鎖
在 Namenode 元數(shù)據(jù)管理這塊,HDFS 使用了多線程去實現(xiàn)的,很多地方加了使用 synchronized 加了鎖,但是它并沒有對所有代碼加鎖,而是只對有線程安全問題的地方加鎖。
這塊具體的需要看源碼。
4. SecondaryNameNode 作用
在 HDFS 中 還有一個 服務(wù)叫 SecondaryNameNode,在HDFS1中,他的作用很重要,主要是為了合并 Fsimage 和 Editlog 的。
在講 SecondaryNameNode 之前,先說下 Fsimage 和 Editlog 。
在上面我們介紹過,其實 Namendoe 的元數(shù)據(jù)是存儲在磁盤上的,實際上所有的歷史元數(shù)據(jù)都會在 Fsimage 文件中,而新增的元數(shù)據(jù)信息是存儲在 Editlog 中的。當(dāng) Namenode 啟動的時候是會合并 Fsimage 和 Editlog 文件,并且把他們都讀入內(nèi)存中。
這就有個問題,如果 Editlog 文件過多(Editlog 可以有很多個)了,在合并的時候就會很耗時,然后拖慢 Namenode 的啟動,所以防止 Editlog 文件過多,就引入 SecondaryNameNode 服務(wù),定期合并 Fsimage 和 Edit 文件。
具體的合并流程如圖:

SecondaryNameNode 本地最開始也有一個與Namenode一樣的 Fsimage 文件,然后定期去拉取 Editlog 文件到本地,然后與自己的 Fsimage 合并,合并成功后,去替換 Namenode 中的 Fsimage ,并刪除已經(jīng)合并的 Editlog 文件