HDFS的基礎(chǔ)總結(jié)及架構(gòu)演進
## 前言 截取知識星球的分享出來,也是對之前的 HDFS 進行一個補充,順帶讓大家復(fù)習(xí)一下 前面兩篇 HDFS 在這里: [帶你入坑大數(shù)據(jù)(一) --- HDFS基礎(chǔ)概念篇] [帶你入坑大數(shù)據(jù)(二) --- HDFS的讀寫流程和一些重要策略] ## Coutent ### 分散存儲,冗余存儲 這兩點我可以展開說明一下,首先我們要清楚,HDFS里面的數(shù)據(jù),分為**真實數(shù)據(jù)**和**元數(shù)據(jù)**兩種,當(dāng)然這里面元數(shù)據(jù)是在 Namenode 里面的,而真實數(shù)據(jù)是存儲在 Datanode 里面的。 比如我們現(xiàn)在要存儲一個大文件,分散存儲的意思就是,會將這個文件拆分成一個個的數(shù)據(jù)塊block,分別獨立存放在某個 Datanode 中。那此時問題就來了,你怎么知道哪個文件是由哪些數(shù)據(jù)塊組成呢?而且這些數(shù)據(jù)塊又分別存在哪些 Datanode 上呢?
這就是元數(shù)據(jù)所起到的作用。 元數(shù)據(jù)存儲其實是在內(nèi)存和磁盤都存儲了一份的,存儲在內(nèi)存的考量主要就是提高響應(yīng)速度,而存磁盤是為了保證元數(shù)據(jù)的安全。而這樣導(dǎo)致的問題就是:如何保證內(nèi)存和磁盤的數(shù)據(jù)一致性問題?這塊可以去學(xué)習(xí)一下 Redis 的做法,既保證效率又保證安全。 而且為什么說HDFS不適合存儲小文件,甚至說我們會有很多小文件的合并機制,那是因為元數(shù)據(jù)并不是一個文件一條元數(shù)據(jù),而是每一個數(shù)據(jù)塊都會對應(yīng)有一個相關(guān)的元數(shù)據(jù)描述,而每個數(shù)據(jù)塊的元數(shù)據(jù)大小將近150字節(jié),這好比說我們往HDFS存一個100M的視頻,對應(yīng)一條150byte的元數(shù)據(jù),如果存100張1M的圖片,就會有對應(yīng)100條150byte的元數(shù)據(jù),所以這個資源的浪費是十分可怕的。
而冗余存儲就是我們的block會有副本機制,這個副本的存儲套路是機架存儲策略 ### 機架存儲策略 實際機房中,會有機架,每個機架上會有若干臺服務(wù)器。一般來說我們會把一個block的3個副本分別按照下述方法進行存儲:
1. 第一個副本就存儲在一個機架A上 第二個副本存儲在和這個block塊不同機架(比如機架B)的一個服務(wù)器上
2. 存儲第2個副本時會優(yōu)先把副本存儲在不同的機架上,這是為了防止出現(xiàn)一個機架斷電的情況,如果副本也存儲在同機架上的不同服務(wù)器上,這時候數(shù)據(jù)就可能丟失了。
3. 第三個副本存儲在機架B的另外一個服務(wù)器上(注意副本2,3都存儲在了機架B) 為什么會這么選擇,因為如果我們把副本3也放在另外一個機架C上,副本2和副本3之間的通信就需要副本2通過它的交換機去聯(lián)系總交換機,然后總交換機去聯(lián)系機架C的交換機,需要走的路線非常長,而且機房中的帶寬資源非常寶貴,如果處于高并發(fā)的情況,很容易就把機房的帶寬打滿,此時整一個集群的響應(yīng)速度會急劇下降,這時候服務(wù)就會出現(xiàn)問題了。 當(dāng)然我們的副本數(shù)也是可以手動通過命令增加的,在客戶端訪問量多的時候,可以適當(dāng)分配一下壓力 $ hadoop fs -setrep -R
4 path + FileName setrep的意思其實就是set replication,設(shè)置副本數(shù)的縮寫,上面命令就是將副本數(shù)設(shè)置成4份了,后面跟著文件路徑和文件名即可 客戶端的交互全部都是和 Namenode 打交道的,這點和 Kafka 一樣,永遠都是和 leader 打交道,而不是和 follower。但是你要知道,正常的實現(xiàn)數(shù)據(jù)的上傳下載的功能確實是走的 Datanode。
HDFS 的架構(gòu) HDFS的架構(gòu):主從架構(gòu),三大角色
1. Namenode作為集群的老大,掌管HDFS文件系統(tǒng)的元數(shù)據(jù),處理客戶端讀寫請求,HDFS的集群內(nèi)部數(shù)據(jù)安全及負載均衡等 2. Datanode存儲整個集群的所有數(shù)據(jù)塊,處理真正的數(shù)據(jù)讀寫
3. SecondaryNamenode嚴格意義上來說并不屬于namenode的備份節(jié)點,它主要起到的作用其實是替namenode分擔(dān)壓力,降低負載(元數(shù)據(jù)的編輯日志合并,也就是edits log)之用
心跳機制 ![](https://user-gold-cdn.xitu.io/2020/7/3/1731456b4df8c774?w=916&h=445&f=png&s=129381) 心跳機制解決了HDFS集群間的通信問題,還是NameNode命令DataNode執(zhí)行操作的途徑 1. master namenode啟動之后,會開一個ipc server 2. DataNode啟動,連接NameNode,每隔3s向NameNode發(fā)送一個心跳,并攜帶狀態(tài)信息 3. NameNode通過對這個心跳的返回值來給DataNode傳達任務(wù)指令 #### 心跳機制的作用: 1.NameNode 全權(quán)管理數(shù)據(jù)塊的復(fù)制,它周期性從集群中的每個 DataNode 接收心跳信號和 block 狀態(tài)報告,接收到心跳信號意味著該 DataNode 節(jié)點工作正常,塊狀態(tài)報告包含了該 DataNode 上所有數(shù)據(jù)塊的列表 2.DataNode啟動時向 NameNode 注冊,通過后周期性地向 NameNode 上報 block 報告,每3秒向 NameNode 發(fā)送一次心跳,NameNode 返回對該 DataNode 的指令,如將數(shù)據(jù)塊復(fù)制到另一臺機器,或刪除某個數(shù)據(jù)塊等···而當(dāng)某一個 DataNode 超過10min還沒向 NameNode 發(fā)送心跳,此時 NameNode 就會判定該 DataNode 不可用,此時客戶端的讀寫操作就不會再傳達到該 DataNode 上
安全模式 3.hadoop 集群剛開始啟動時會進入安全模式(99.99%),就用到了心跳機制,其實就是在集群剛啟動的時候,每一個 DataNode 都會向 NameNode 發(fā)送 block 報告,NameNode 會統(tǒng)計它們上報的總block數(shù),除以一開始知道的總個數(shù)total,當(dāng) block/total < 99.99% 時,會觸發(fā)安全模式,安全模式下客戶端就沒法向HDFS寫數(shù)據(jù),只能進行讀數(shù)據(jù)。 而且補充一點,Namenode感知Datanode掉線死亡時間的計算公式為: timeout = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval HDFS默認超時時間為630秒,因為默認的 heartbeat.recheck.interval 為5分鐘,而 dfs.heartbeat.interval 默認為3秒,而這兩個參數(shù)理解起來也很簡單,一個是重新檢查的時間間隔,而另一個是每n秒發(fā)送一次心跳的參數(shù),等待10次,不行拉倒。
安全模式的補充 安全模式不僅僅是集群剛啟動時等所有的Datanode匯報這一種情況會進入安全模式的,還有就是HDFS數(shù)據(jù)塊丟失達到一個比例的時候,也會自動進入,當(dāng)然我們也可以手動去進入安全模式。這個比例默認是0.1%,1000個塊丟1個已經(jīng)很嚴重的事件了。 可以通過 start-balancer.sh 來讓HDFS做負載均衡,可是要注意,這個命令是存在一定的問題的,這和Java的垃圾回收機制中的 System.gc() 是一樣的。
我告訴你,現(xiàn)在要去進行垃圾回收了,可是 JVM 壓根就不理咱們,為啥呢?它只會在自己有空,合適的時間去做垃圾回收,而 start-balancer.sh 就也是一樣的套路,利用剩余的帶寬去做這個事情。 而這個操作也有一定的標(biāo)準,根據(jù)一個數(shù)值n規(guī)定。每一個節(jié)點都計算出一個磁盤的占用量,占用量最大-占用量最小 = 這個標(biāo)準數(shù)值n即可。默認是10%,這樣就很好理解了吧。而且這個負載均衡的操作是一定不能影響到客戶端的讀寫業(yè)務(wù)的,所以HDFS默認會不允許balance操作占用太多的帶寬。但是我們可以進行手動調(diào)整 hdfs dfs admin -setBalancerBandwidth newbandwidth newbandwidth 的默認單位是字節(jié),所以這個東西自己根據(jù)需求調(diào)整即可。默認是1M每秒的。
HDFS的缺陷及演進 Hadoop1 版本剛出來的時候是為了解決兩個問題:一個是海量數(shù)據(jù)如何存儲的問題,一個是海量數(shù)據(jù)如何計算的問題 Namenode的工作:
1. 管理集群元數(shù)據(jù)信息(文件目錄樹): 可以簡單理解為,一個文件被分為了幾個block塊,而這些block塊又分別存儲在了哪些位置。
2. Namenode為了快速響應(yīng)用戶的操作請求,所以將元數(shù)據(jù)加載到了內(nèi)存里面 Datanode的工作:
1. 存儲數(shù)據(jù),把上傳的數(shù)據(jù)劃分為固定大小的文件塊,hadoop1默認64,之后是128M 2. 為了保證數(shù)據(jù)安全,每個文件塊默認都有三個副本,這里的三個副本其實是總共3個的意思,而不是一份原始3個備份總數(shù)為4 #### HDFS1的架構(gòu)缺陷 1. 單點故障問題:Namenode掛掉集群就廢了
2. 內(nèi)存受限問題:就是Namenode的元數(shù)據(jù)信息撐爆了內(nèi)存的情況下,整個集群就癱瘓了 #### QJM方案解決單點故障問題 其實本身還存在一個多個Namenode共用一個共享目錄的解決方式,但是這樣也會存在共享目錄出現(xiàn)問題的情況,所以就無法滿足我們的要求 QJM方案如下:我們單獨建立一個JournalNode集群,然后由它們來解決單點故障的問題,JournalNode之間數(shù)據(jù)是一致的,我們的主Namenode,也就是active Namenode對元數(shù)據(jù)進行修改的時候,會對JournalNode進行寫入操作,然后再由Standby Namenode去進行同步以達到主從Namenode的數(shù)據(jù)一致。
![](https://user-gold-cdn.xitu.io/2020/7/3/173143a1a758a9c8?w=780&h=516&f=png&s=52215) 但是現(xiàn)在還是存在一個問題,就是我們需要手動將standby切換成active,所以此時我們就引入了Zookeeper來解決這個問題,其實存在一些企業(yè)會有直接不使用JournalNode而直接使用Zookeeper來代替的方案,因為JournalNode的任務(wù)就是保證這些節(jié)點的數(shù)據(jù)一致而已,這個特點通過Zookeeper的原子廣播協(xié)議是完全可以做到的。
[](https://user-gold-cdn.xitu.io/2020/7/3/1731463f9eded92e?w=787&h=678&f=png&s=69453) 此時在Zookeeper中創(chuàng)建一個鎖的目錄,然后NameNode啟動的時候都會過去搶占鎖,兩個NameNode誰先搶到,誰就是active狀態(tài)。而且每一個NameNode上還有一個ZKFC的服務(wù),持續(xù)監(jiān)聽NameNode的健康狀態(tài),如果active NameNode出現(xiàn)問題,ZKFC將會報告給Zookeeper,然后Zookeeper會將鎖分配給standby的NameNode上。使其自動切換為active狀態(tài)。此時就是HDFS2的架構(gòu)了。 #### JournalNode推薦 因為其實JournalNode的任務(wù)并不重,所以不需要太過于龐大的集群 200個節(jié)點以下 ---> 3個 200~2000個節(jié)點 ---> 5個 #### 聯(lián)邦解決內(nèi)存受限問題 ![](https://user-gold-cdn.xitu.io/2020/7/3/17314652201b40b1?w=993&h=725&f=png&s=88902) 如上圖,就是等于一個橫向擴展的方式,既然一個Namenode會撐爆,那么多個Namenode,負責(zé)存儲不同的元數(shù)據(jù)信息即可。
這就好比我們的C,D,E,F盤,C盤是存放系統(tǒng)的一些東西,D盤拿來裝軟件,E盤拿來放電影是一個道理。而且聯(lián)邦機制,HDFS 自動路由。用戶不用關(guān)心是具體是哪個 namenode 去進行存儲了 此時作一個小總結(jié),active+standby 的Namenode形成一組,目的是做高可用,防止單點故障。而多組active+standby形成聯(lián)邦,目的是解決單組內(nèi)存不夠的問題。 #### HDFS如何管理元數(shù)據(jù) 還記得我們搭建集群的時候,在啟動集群之前需要做一步“格式化Namenode”的操作嗎?這一步的目的就是在磁盤上生成fsimage,也就是我們的元數(shù)據(jù)目錄信息。此時再把這個元數(shù)據(jù)加載到內(nèi)存。
[](https://user-gold-cdn.xitu.io/2020/7/3/1731467460c189a8?w=772&h=598&f=png&s=54508) 如下圖,此時假如客戶端要上傳文件,它就會和內(nèi)存中的fsimage進行交互,增加一條元數(shù)據(jù)信息,這個操作就會寫入到一份 edit log 中去,顧名思義就是編輯日志。而磁盤中的fsimage此時還是最一開始的那份,不像內(nèi)存中的fsimage是隨時在變化的。此時 內(nèi)存fsimage = 磁盤fsimage + edit log 此時如果我停止了服務(wù),內(nèi)存中的fsimage被銷毀,此時我只需要將edit log中的記錄回放,刷寫成新的一份fsimage,此時集群再次啟動,再加載到內(nèi)存中,就恢復(fù)成為我們停止服務(wù)前的狀態(tài)了。 ![](https://user-gold-cdn.xitu.io/2020/7/3/1731468364b03136?w=1240&h=687&f=png&s=129668) 此時引入SecondaryNamenode,它的作用就是提高Namenode的恢復(fù)速度,大致對操作步驟進行一個闡述:
1. SecondaryNameNode 會通過http get方式把edits log和fsimage的信息拉取過來
2. 在SecondaryNameNode中把edits log和fsimage做一個合并,產(chǎn)生一個新的文件叫做 fsimage.ckpt
3. 在SecondaryNameNode中合并完成之后,再回傳給NameNode里面
4. 這時大概率會有客戶端還在對NameNode進行讀寫操作,也會產(chǎn)生新的日志,此時按照先前未引入SNN的套路繼續(xù)即可。 在HA方案中這個行為可以交給standby去完成。
雙緩沖機制 Namenode里面的元數(shù)據(jù)是以兩種狀態(tài)進行存儲的: 第一狀態(tài)即是存儲在內(nèi)存里面,也就是剛剛所提到的目錄樹,它就是一個list,在內(nèi)存里面更新元數(shù)據(jù)速度是很快的。但是如果僅僅只在內(nèi)存里存放元數(shù)據(jù),數(shù)據(jù)是不太安全的。
所以我們在磁盤上也會存儲一份元數(shù)據(jù),可是此時問題就出現(xiàn)了,我們需要把數(shù)據(jù)寫進磁盤,這個性能肯定是不太好的呀??蒒ameNode作為整個集群的老大,在hadoop上進行hive,HBASE,spark,flink等計算,這些數(shù)據(jù)都會不停給NameNode施壓寫元數(shù)據(jù),一天下來一億條元數(shù)據(jù)都是可能的,所以NameNode的設(shè)計肯定是要支持超高并發(fā)的,可是寫磁盤這操作是非常非常慢的,一秒幾十或者最多幾百都已經(jīng)封頂了,那現(xiàn)在咋辦? ![](https://user-gold-cdn.xitu.io/2020/7/3/1731469118400032?w=809&h=304&f=png&s=87341) 首先我們的客戶端(這里指的是hive,hbase,spark···都沒關(guān)系)所產(chǎn)生的數(shù)據(jù)將會走兩個流程,第一個流程會向內(nèi)存處寫入數(shù)據(jù),這個過程非???,也不難理解 ![](https://user-gold-cdn.xitu.io/2020/7/3/173146a8a8b07c92?w=812&h=395&f=png&s=108401) 這時候肯定就不能直接寫內(nèi)存了,畢竟我們是明知道這東西非常慢的,真的要等它一條條數(shù)據(jù)寫到磁盤,那特么我們都可以雙手離開鼠標(biāo)鍵盤下班走人了。
那NameNode一個東西不行就整個集群都不行了,那現(xiàn)在我們該如何解決? ![](https://user-gold-cdn.xitu.io/2020/7/3/173146ae924df870?w=887&h=629&f=png&s=247862) 雙緩沖機制就是指我們將會開辟兩份一模一樣的內(nèi)存空間,一個為bufCurrent,產(chǎn)生的數(shù)據(jù)會直接寫入到這個bufCurrent,而另一個叫bufReady,在bufCurrent數(shù)據(jù)寫入(其實這里可能不止一條數(shù)據(jù),等下會說明)后,兩片內(nèi)存就會exchange(交換)。
然后之前的bufCurrent就負責(zé)往磁盤上寫入數(shù)據(jù),之前的bufReady就繼續(xù)接收客戶端寫入的數(shù)據(jù)。其實就是將向磁盤寫數(shù)據(jù)的任務(wù)交給了后臺去做。這個做法,在JUC里面也有用到 而且在此基礎(chǔ)上,hadoop會給每一個元數(shù)據(jù)信息的修改賦予一個事務(wù)ID號,保證操作都是有序的。這也是出于數(shù)據(jù)的安全考慮。這樣整個系統(tǒng)要求的內(nèi)存會非常大,所以這關(guān)乎一個hadoop的優(yōu)化問題,在之后將會提及。
聲明:免責(zé)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻自行上傳,本網(wǎng)站不擁有所有權(quán),也不承認相關(guān)法律責(zé)任。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,請發(fā)
送郵件至:operations@xinnet.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,本站將立刻刪除涉嫌侵權(quán)內(nèi)容。本站原創(chuàng)內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時
需注明出處:新網(wǎng)idc知識百科