Hadoop的第一個產品是HDFS,可以說分散式文件存儲是分散式計算的基礎,也可見分散式文件存儲的重要性。如果我們將大數據計算比作烹飪,那麼數據就是食材,而Hadoop分散式文件系統HDFS就是燒菜的那口大鍋。這些年來,各種計算框架、各種演算法、各種應用場景不斷推陳出新,讓人眼花繚亂,但是大數據存儲的 ...
Hadoop的第一個產品是HDFS,可以說分散式文件存儲是分散式計算的基礎,也可見分散式文件存儲的重要性。如果我們將大數據計算比作烹飪,那麼數據就是食材,而Hadoop分散式文件系統HDFS就是燒菜的那口大鍋。這些年來,各種計算框架、各種演算法、各種應用場景不斷推陳出新,讓人眼花繚亂,但是大數據存儲的王者依然是HDFS。
為什麼HDFS的地位如此穩固呢?在整個大數據體系裡面,最寶貴、最難以代替的資產就是數據,大數據所有的一切都要圍繞數據展開。HDFS作為最早的大數據存儲系統,存儲著寶貴的數據資產,各種新的演算法、框架要想得到人們的廣泛使用,必須支持HDFS才能獲取已經存儲在裡面的數據。所以大數據技術越發展,新技術越多,HDFS得到的支持越多,我們越離不開HDFS。HDFS也許不是最好的大數據存儲技術,但依然最重要的大數據存儲技術。
那我們就從HDFS的原理說起,今天我們來聊聊HDFS是如何實現大數據高速、可靠的存儲和訪問的。
Hadoop分散式文件系統HDFS的設計目標是管理數以千計的伺服器、數以萬計的磁碟,將這麼大規模的伺服器計算資源當作一個單一的存儲系統進行管理,對應用程式提供數以PB計的存儲容量,讓應用程式像使用普通文件系統一樣存儲大規模的文件數據。
如何設計這樣一個分散式文件系統?其實思路很簡單。
我們想想RAID磁碟陣列存儲,RAID將數據分片後在多塊磁碟上併發進行讀寫訪問,從而提高了存儲容量、加快了訪問速度,並通過數據的冗餘校驗提高了數據的可靠性,即使某塊磁碟損壞也不會丟失數據。將RAID的設計理念擴大到整個分散式伺服器集群,就產生了分散式文件系統,Hadoop分散式文件系統的核心原理就是如此。
和RAID在多個磁碟上進行文件存儲及並行讀寫的思路一樣,HDFS是在一個大規模分散式伺服器集群上,對數據分片後進行並行讀寫及冗餘存儲。因為HDFS可以部署在一個比較大的伺服器集群上,集群中所有伺服器的磁碟都可供HDFS使用,所以整個HDFS的存儲空間可以達到PB級容量。
上圖是HDFS的架構圖,從圖中你可以看到HDFS的關鍵組件有兩個,一個是DataNode,一個是NameNode。
DataNode負責文件數據的存儲和讀寫操作,HDFS將文件數據分割成若幹數據塊(Block),每個DataNode存儲一部分數據塊,這樣文件就分佈存儲在整個HDFS伺服器集群中。應用程式客戶端(Client)可以並行對這些數據塊進行訪問,從而使得HDFS可以在伺服器集群規模上實現數據並行訪問,極大地提高了訪問速度。
在實踐中,HDFS集群的DataNode伺服器會有很多台,一般在幾百台到幾千台這樣的規模,每台伺服器配有數塊磁碟,整個集群的存儲容量大概在幾PB到數百PB。
NameNode負責整個分散式文件系統的元數據(MetaData)管理,也就是文件路徑名、數據塊的ID以及存儲位置等信息。HDFS為了保證數據的高可用,會將一個數據塊複製為多份(預設情況為3份),並將多份相同的數據塊存儲在不同的伺服器上,甚至不同的機架上。這樣當有磁碟損壞,或者某個DataNode伺服器宕機,甚至某個交換機宕機,導致其存儲的數據塊不能訪問的時候,客戶端會查找其備份的數據塊進行訪問。
下麵這張圖是數據塊多份複製存儲的示意,圖中對於文件/users/sameerp/data/part-0,其複製備份數設置為2,存儲的BlockID分別為1、3。Block1的兩個備份存儲在DataNode0和DataNode2兩個伺服器上,Block3的兩個備份存儲DataNode4和DataNode6兩個伺服器上,上述任何一臺伺服器宕機後,每個數據塊都至少還有一個備份存在,不會影響對文件/users/sameerp/data/part-0的訪問。
和RAID一樣,數據分成若幹數據塊後存儲到不同伺服器上,可以實現數據大容量存儲,並且不同分片的數據可以並行進行讀/寫操作,進而實現數據的高速訪問。你可以看到,HDFS的大容量存儲和高速訪問相對比較容易實現,但是HDFS是如何保證存儲的高可用性呢?
我們嘗試從不同層面來討論一下HDFS的高可用設計。
1.數據存儲故障容錯
磁碟介質在存儲過程中受環境或者老化影響,其存儲的數據可能會出現錯亂。HDFS的應對措施是,對於存儲在DataNode上的數據塊,計算並存儲校驗和(CheckSum)。在讀取數據的時候,重新計算讀取出來的數據的校驗和,如果校驗不正確就拋出異常,應用程式捕獲異常後就到其他DataNode上讀取備份數據。
2.磁碟故障容錯
如果DataNode監測到本機的某塊磁碟損壞,就將該塊磁碟上存儲的所有BlockID報告給NameNode,NameNode檢查這些數據塊還在哪些DataNode上有備份,通知相應的DataNode伺服器將對應的數據塊複製到其他伺服器上,以保證數據塊的備份數滿足要求。
3.DataNode故障容錯
DataNode會通過心跳和NameNode保持通信,如果DataNode超時未發送心跳,NameNode就會認為這個DataNode已經宕機失效,立即查找這個DataNode上存儲的數據塊有哪些,以及這些數據塊還存儲在哪些伺服器上,隨後通知這些伺服器再複製一份數據塊到其他伺服器上,保證HDFS存儲的數據塊備份數符合用戶設置的數目,即使再出現伺服器宕機,也不會丟失數據。
4.NameNode故障容錯
NameNode是整個HDFS的核心,記錄著HDFS文件分配表信息,所有的文件路徑和數據塊存儲信息都保存在NameNode,如果NameNode故障,整個HDFS系統集群都無法使用;如果NameNode上記錄的數據丟失,整個集群所有DataNode存儲的數據也就沒用了。
所以,NameNode高可用容錯能力非常重要。NameNode採用主從熱備的方式提供高可用服務,請看下圖。
集群部署兩台NameNode伺服器,一臺作為主伺服器提供服務,一臺作為從伺服器進行熱備,兩台伺服器通過ZooKeeper選舉,主要是通過爭奪znode鎖資源,決定誰是主伺服器。而DataNode則會向兩個NameNode同時發送心跳數據,但是只有主NameNode才能向DataNode返回控制信息。
正常運行期間,主從NameNode之間通過一個共用存儲系統shared edits來同步文件系統的元數據信息。當主NameNode伺服器宕機,從NameNode會通過ZooKeeper升級成為主伺服器,並保證HDFS集群的元數據信息,也就是文件分配表信息完整一致。
對於一個軟體系統而言,性能差一點,用戶也許可以接受;使用體驗差,也許也能忍受。但是如果可用性差,經常出故障導致不可用,那就比較麻煩了;如果出現重要數據丟失,那開發工程師絕對是攤上大事了。
而分散式系統可能出故障地方又非常多,記憶體、CPU、主板、磁碟會損壞,伺服器會宕機,網路會中斷,機房會停電,所有這些都可能會引起軟體系統的不可用,甚至數據永久丟失。
所以在設計分散式系統的時候,軟體工程師一定要繃緊可用性這根弦,思考在各種可能的故障情況下,如何保證整個軟體系統依然是可用的。
根據我的經驗,一般說來,常用的保證系統可用性的策略有冗餘備份、失效轉移和降級限流。雖然這3種策略你可能早已耳熟能詳,但還是有一些容易被忽略的地方。
比如冗餘備份,任何程式、任何數據,都至少要有一個備份,也就是說程式至少要部署到兩台伺服器,數據至少要備份到另一臺伺服器上。此外,稍有規模的互聯網企業都會建設多個數據中心,數據中心之間互相進行備份,用戶請求可能會被分發到任何一個數據中心,即所謂的異地多活,在遭遇地域性的重大故障和自然災害的時候,依然保證應用的高可用。
當要訪問的程式或者數據無法訪問時,需要將訪問請求轉移到備份的程式或者數據所在的伺服器上,這也就是失效轉移。失效轉移你應該註意的是失效的鑒定,像NameNode這樣主從伺服器管理同一份數據的場景,如果從伺服器錯誤地以為主伺服器宕機而接管集群管理,會出現主從伺服器一起對DataNode發送指令,進而導致集群混亂,也就是所謂的“腦裂”。這也是這類場景選舉主伺服器時,引入ZooKeeper的原因。ZooKeeper的工作原理,我將會在後面專門分析。
當大量的用戶請求或者數據處理請求到達的時候,由於計算資源有限,可能無法處理如此大量的請求,進而導致資源耗盡,系統崩潰。這種情況下,可以拒絕部分請求,即進行限流;也可以關閉部分功能,降低資源消耗,即進行降級。限流是互聯網應用的常備功能,因為超出負載能力的訪問流量在何時會突然到來,你根本無法預料,所以必須提前做好準備,當遇到突發高峰流量時,就可以立即啟動限流。而降級通常是為可預知的場景準備的,比如電商的“雙十一”促銷,為了保障促銷活動期間應用的核心功能能夠正常運行,比如下單功能,可以對系統進行降級處理,關閉部分非重要功能,比如商品評價功能。
我們小結一下,看看HDFS是如何通過大規模分散式伺服器集群實現數據的大容量、高速、可靠存儲、訪問的。
1.文件數據以數據塊的方式進行切分,數據塊可以存儲在集群任意DataNode伺服器上,所以HDFS存儲的文件可以非常大,一個文件理論上可以占據整個HDFS伺服器集群上的所有磁碟,實現了大容量存儲。
2.HDFS一般的訪問模式是通過MapReduce程式在計算時讀取,MapReduce對輸入數據進行分片讀取,通常一個分片就是一個數據塊,每個數據塊分配一個計算進程,這樣就可以同時啟動很多進程對一個HDFS文件的多個數據塊進行併發訪問,從而實現數據的高速訪問。關於MapReduce的具體處理過程,我們會在專欄後面詳細討論。
3.DataNode存儲的數據塊會進行複製,使每個數據塊在集群里有多個備份,保證了數據的可靠性,並通過一系列的故障容錯手段實現HDFS系統中主要組件的高可用,進而保證數據和整個系統的高可用。