好程式員大資料教育訓練分享之HDFS設計思想和相關概念:一、HDFS簡介
1、簡單介紹
HDFS(Hadoop Distributed FileSystem),是Hadoop項目的兩大核心之一,源自于Google于2003年10月發表的GFS論文,是對GFS的開源實作。HDFS在最開始是作為Apache Nutch搜尋引擎項目的基礎架構而開發的。
HDFS在設計之初,就是要運作在通用硬體(commodity hardware)上,即廉價的大型伺服器叢集上,是以,在設計上就把硬體故障作為一種常态來考慮,可以保證在部分硬體發生故障的情況下,仍然能夠保證檔案系統的整體可用性和可靠性。
HDFS有一下特點:
HDFS是一個高度容錯性的系統,适合部署在廉價的機器上的分布式檔案系統。
HDFS能提供高吞吐量的資料通路,非常适合大規模資料集上的應用。
HDFS放寬了一部分POSIX限制,來實作流式讀取檔案系統資料的目的。
HDFS也是一個易于擴充的分布式檔案系統
2、HDFS設計目标
a、大規模資料集
HDFS用來處理很大的資料集。HDFS上的檔案,大小一般都在GB至TB。是以同時,HDFS應該能提供整體較高的資料傳輸帶寬,能在一個叢集裡擴充到數百個節點。一個單一的HDFS執行個體應該能支撐千萬計的檔案。目前在實際應用中,HDFS已經能用來存儲管理PB級的資料了。
b、硬體錯誤
我們應該知道,硬體元件發生故障是常态,而非異常情況。HDFS可能由成百上千的伺服器組成,每一個伺服器都是廉價通用的普通硬體,任何一個元件都有可能一直失效,是以錯誤檢測和快速、自動恢複是HDFS的核心架構目标,同時能夠通過自身持續的狀态監控快速檢測備援并恢複失效的元件。
c、流式資料通路
流式資料,特點就是,像流水一樣,不是一次過來而是一點一點“流”過來,而處理流式資料也是一點一點處理。
HDFS的設計要求是:能夠高速率、大批量的處理資料,更多地響應"一次寫入、多次讀取"這樣的任務。在HDFS上一個資料集,會被複制分發到不同的存儲節點中。而各式各樣的分析任務多數情況下,都會涉及資料集中的大部分資料。為了提高資料的吞吐量,Hadoop放寬了POSIX的限制,使用流式通路來進行高效的分析工作
d、簡化一緻性模型
HDFS應用需要一個“一次寫入多次讀取”的檔案通路模型。一個檔案經過建立、寫入和關閉之後就不需要改變了。這一假設簡化了資料一緻性問題,并且使高吞吐量的資料通路成為可能。MapReduce應用或網絡爬蟲應用都非常适合這個模型。目前還有計劃在将來擴充這個模型,使之支援檔案的附加寫操作。
e、移動計算代價比移動資料代價低
一個應用請求的計算,離它操作的資料越近就越高效,這在資料達到海量級别的時候更是如此。将計算移動到資料附近,比之将資料移動到應用所在之處顯然更好,HDFS提供給應用這樣的接口。
f、可移植性
HDFS在設計時就考慮到平台的可移植性,這種特性友善了HDFS作為大規模資料應用平台的推廣。
3、HDFS的優缺點
通過上述的介紹,我們可以發現HDFS的優點是:
a、高容錯性:資料自動儲存多個副本,副本丢失後,會自動恢複。
b、适合批處理:移動計算而非資料、資料位置需要暴露給計算架構。
c、适合大資料處理:GB、TB、甚至PB級資料、百萬規模以上的檔案數量,1000以上節點規模。
d、流式檔案通路:一次性寫入,多次讀取;保證資料一緻性。
e、可建構在廉價機器上:通過多副本提高可靠性,提供了容錯和恢複機制。
而HDFS同樣有自己的缺點:
1)不适合低延遲資料通路
HDFS的設計目标有一點是:處理大型資料集,高吞吐率。這勢必要以高延遲為代價的。是以HDFS不适合處理一些使用者要求時間比較短的低延遲應用請求。
2)不适合小檔案存取
一是是以存取大量小檔案需要消耗大量的尋地時間(比如拷貝大量小檔案與拷貝同等大小的一個大檔案) 。
二是因為namenode把元資訊存儲在記憶體中,一個節點的記憶體是有限的。一個block元資訊的記憶體消耗大約是150 byte。而存儲1億個block和1億個小檔案都會消耗掉namenode 20GB記憶體,哪個适合?當然是1億個block(大檔案)更省記憶體。
3)不适合并發寫入、檔案随機修改
HDFS上的檔案隻能有一個寫者,也僅僅支援append操作,不支援多使用者對同一檔案的寫操作,以及在檔案任意位置進行修改。
二、HDFS設計思想
現在想象一下這種情況:有四個檔案 0.5TB的file1,1.2TB的file2,50GB的file3,100GB的file4;有7個伺服器,每個伺服器上有10個1TB的硬碟。
在存儲方式上,我們可以将這四個檔案存儲在同一個伺服器上(當然大于1TB的檔案需要切分),我們需要使用一個檔案來記錄這種存儲的映射關系吧。使用者是可以通過這種映射關系來找到節點硬碟相應的檔案的。那麼缺點也就暴露了出來:
第一、負載不均衡。因為檔案大小不一緻,勢必會導緻有的節點磁盤的使用率高,有的節點磁盤使用率低。
第二、網絡瓶頸問題。一個過大的檔案存儲在一個節點磁盤上,當有并行處理時,每個線程都需要從這個節點磁盤上讀取這個檔案的内容,那麼就會出現網絡瓶頸,不利于分布式的資料處理。
我們來看看HDFS的設計思想:以下圖為例,來進行解釋。
HDFS将50G的檔案file3切成多個Block(存儲塊),每一個Block的大小都是固定的,比如128MB,它把這多個資料塊以多副本的行式存儲在各個節點上 ,再使用一個檔案把哪個塊存儲在哪些節點上的映射關系存儲起來。有了這樣的映射關系,使用者讀取檔案的時候就會很容易讀取到。每個節點上都有這樣的Block資料,它會分開網絡瓶頸,利于分布式計算,解決了上面的第二個問題。因為每個塊的大小是一樣的,是以很容易實作負載均衡,解決了上面的第一個問題。
三、HDFS相關概念
1、塊(Block)概念
在我們熟知的Windows、Linux等系統上,檔案系統會将磁盤空間劃分為每512位元組一組,我們稱之為"磁盤塊",它是檔案系統讀寫操作的最小機關。而檔案系統的資料塊(Block)一般是磁盤塊的整數倍,即每次讀寫的資料量必須是磁盤塊的整數倍。
在傳統的檔案系統中,為了提高磁盤的讀寫效率,一般以資料塊為機關,而不是以位元組為機關,比如機械硬碟包含了磁頭和轉動部件,在讀取資料時有一個尋道的過程,通國轉動盤片和移動磁頭的位置,來找到資料在機械硬碟中的存儲位置,然後才能進行讀寫。在I/O開銷中,機械硬碟的尋址時間時最耗時的部分,一旦找到第一條記錄,剩下的順序讀取效率是非常高的,是以以塊為機關讀寫資料,可以把磁盤尋道時間分攤到大量資料中。
HDFS同樣引入了塊(Block)的概念,塊是HDFS系統當中的最小存儲機關,在hadoop2.0中預設大小為128MB。在HDFS上的檔案會被拆分成多個塊,每個塊作為獨立的單元進行存儲。多個塊存放在不同的DataNode上,整個過程中 HDFS系統會保證一個塊存儲在一個資料節點上 。但值得注意的是 如果某檔案大小或者檔案的最後一個塊沒有到達128M,則不會占據整個塊空間 。
當然塊大小可以在配置檔案中hdfs-default.xml中進行修改(此值可以修改)
dfs.blocksize
134217728
預設塊大小,以位元組為機關。可以使用以下字尾(不區分大小寫):k,m,g,t,p,e以重新指定大小(例如128k, 512m, 1g等)
dfs.namenode.fs-limits.min-block-size
1048576
以位元組為機關的最小塊大小,由Namenode在建立時強制執行時間。這可以防止意外建立帶有小塊的檔案可以降級的大小(以及許多塊)的性能。
<name>dfs.namenode.fs-limits.max-blocks-per-file</name>
<value>1048576</value>
<description>每個檔案的最大塊數,由寫入時的Namenode執行。這可以防止建立會降低性能的超大檔案</description></property>
HDFS中的NameNode會記錄檔案的各個塊都存放在哪個dataNode上,這些資訊一般也稱為元資訊(MetaInfo) 。元資訊的存儲位置一般由dfs.namenode.name.dir來指定。
dfs.namenode.name.dir
file://${hadoop.tmp.dir}/dfs/name
而datanode是真實存儲檔案塊的節點,塊在datanode的位置一般由dfs.datanode.data.dir來指定。
dfs.datanode.data.dir
file://${hadoop.tmp.dir}/dfs/data
HDFS上的塊為什麼遠遠大與傳統檔案系統,是有原因的。目的是為了最小化尋址開銷時間。
HDFS尋址開銷不僅包括磁盤尋道開銷,還包括資料庫的定位開銷,當用戶端需要通路一個檔案時,首先從名稱節點擷取組成這個檔案的資料塊的位置清單,然後根據位置清單擷取實際存儲各個資料塊的資料節點的位置,最後,資料節點根據資料塊資訊在本地Linux檔案系統中找到對應的檔案,并把資料傳回給用戶端,設計一個比較大的塊,可以把尋址開銷分攤到較多的資料中,相對降低了機關資料的尋址開銷
舉個例子: 塊大小為128MB,預設傳輸效率100M/s ,尋址時間為10ms,那麼尋址時間隻占傳輸時間的1%左右
當然,塊也不能太大,因為另一個核心技術MapReduce的map任務一次隻處理一個資料塊,如果任務太少,勢必會降低工作的并行處理速度。
HDFS的塊概念,在解決了大資料集檔案的存儲同時,不僅解決了檔案存取的網絡瓶頸問題,還
解決了大資料集檔案的存儲:大檔案分塊存儲在多個資料節點上,不必受限于單個節點的存儲容量。
簡化系統設計:塊大小固定,單個節點的塊數量比較少,容易管理。中繼資料可以單獨由其他系統負責管理。
适合資料備份:每個塊可以很容易的備援存儲到多個節點上,提高了系統的容錯性和可用性
2、Namenode和Datanode
HDFS叢集上有兩類節點,一類是管理節點(Namenode),一類是工作節點(Datanode)。而HDFS就是以管理節點-工作節點的模式運作的,在HDFS上,通常有一個Namenode和多個Datanode(一個管理者master,多個工作者slave)。
作為master的NameNode負責管理分布式檔案系統的命名空間(NameSpace),即維護的是檔案系統樹及樹内的檔案和目錄。這些資訊以 兩個核心檔案(fsImage和editlog)的形式持久化在本地磁盤中。
fsImage命名空間鏡像檔案,用于維護檔案系統樹以及檔案樹中所有檔案和目錄的中繼資料;記錄檔檔案editlog中記錄了所有針對檔案的建立、删除、重命名等操作。namenode也記錄了每個檔案的各個塊所在的datanode的位置資訊,但并不持久化存儲這些資訊,而是在系統每次啟動時掃描所datanode重構得到這些資訊,也就是說儲存在運作記憶體中。
Namenode在啟動時,會将FsImage的内容加載到記憶體當中,然後執行EditLog檔案中的各項操作,使得記憶體中的中繼資料保持最新。這個操作完成以後,就會建立一個新的FsImage檔案和一個空的EditLog檔案。名稱節點啟動成功并進入正常運作狀态以後,HDFS中的更新操作都被寫到EditLog,而不是直接寫入FsImage,這是因為對于分布式檔案系統而言,FsImage檔案通常都很龐大,如果所有的更新操作都直接往FsImage檔案中添加,那麼系統就會變得非常緩慢。相對而言,EditLog通常都要遠遠小于FsImage,更新操作寫入到EditLog是非常高效的。名稱節點在啟動的過程中處于“安全模式”,隻能對外提供讀操作,無法提供寫操作。在啟動結束後,系統就會退出安全模式,進入正常運作狀态,對外提供寫操作。
作為slave的Datanode是分布式檔案系統HDFS的工作節點,負責資料塊的存儲和讀取(會根據用戶端或者Namenode的排程來進行資料的存儲和檢索),并且定期向Namenode發送自己所存儲的塊的清單。每個Datanode中的資料會被儲存在本地Linux檔案系統中。
3、SecondaryNamenode
在Namenode運作期間,HDFS會不斷發生更新操作,這些更新操作不會直接寫到fsimage檔案中,而是直接被寫入到editlog檔案的,檔案會越來越大。當Namenode重新開機時,會加載fsimage加載到記憶體中,并且逐條執行editlog中的記錄,editlog檔案大,就會導緻整個過程變得非常緩慢,使得Namenode在啟動過程中長期處于“安全模式”,無法正常對外提供寫操作,影響了使用者的使用。
HDFS采用了SecondaryNameNode這個守護線程,可以定期完成editlog與fsImage的合并操作,減小editlog檔案大小,縮短Namenode重新開機時間;也可以作為Namenode的一個“檢查點”,将儲存Namenode記憶體中的中繼資料資訊,儲存在fsimage鏡像檔案中。