1. 程式人生 > >《Hadoop》"呶呶不休"(一)HDFS概述

《Hadoop》"呶呶不休"(一)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中進行修改(此值可以修改)

<property>
  <name>dfs.blocksize</name>
  <value>134217728</value>
  <description>預設塊大小,以位元組為單位。可以使用以下字尾(不區分大小寫):k,m,g,t,p,e以重新指定大小(例如128k, 512m, 1g等)</description>
</property>

<property>
  <name>dfs.namenode.fs-limits.min-block-size</name>
  <value>1048576</value>
  <description>以位元組為單位的最小塊大小,由Namenode在建立時強制執行時間。這可以防止意外建立帶有小塊的檔案可以降級的大小(以及許多塊)的效能。</description>
</property>

<property>
    <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來指定。

<property>
  <name>dfs.namenode.name.dir</name>
  <value>file://${hadoop.tmp.dir}/dfs/name</value>
</property>

而datanode是真實儲存檔案塊的節點,塊在datanode的位置一般由dfs.datanode.data.dir來指定。

<property>
  <name>dfs.datanode.data.dir</name>
  <value>file://${hadoop.tmp.dir}/dfs/data</value>
</property>

HDFS上的塊為什麼遠遠大與傳統檔案系統,是有原因的。目的是為了最小化定址開銷時間。

HDFS定址開銷不僅包括磁碟尋道開銷,還包括資料庫的定位開銷,當客戶端需要訪問一個檔案時,首先從名稱節點獲取組成這個檔案的資料塊的位置列表,然後根據位置列表獲取實際儲存各個資料塊的資料節點的位置,最後,資料節點根據資料塊資訊在本地Linux檔案系統中找到對應的檔案,並把資料返回給客戶端,設計一個比較大的塊,可以把定址開銷分攤到較多的資料中,相對降低了單位資料的定址開銷

舉個例子:  塊大小為128MB,預設傳輸效率100M/s ,定址時間為10ms,那麼定址時間只佔傳輸時間的1%左右  

當然,塊也不能太大,因為另一個核心技術MapReduce的map任務一次只處理一個數據塊,如果任務太少,勢必會降低工作的並行處理速度。

HDFS的塊概念,在解決了大資料集檔案的儲存同時,不僅解決了檔案存取的網路瓶頸問題,還

1、解決了大資料集檔案的儲存:大檔案分塊儲存在多個數據節點上,不必受限於單個節點的儲存容量。
2、簡化系統設計:塊大小固定,單個節點的塊數量比較少,容易管理。元資料可以單獨由其他系統負責管理。
3、適合資料備份:每個塊可以很容易的冗餘儲存到多個節點上,提高了系統的容錯性和可用性

2、Namenode和Datanode

HDFS叢集上有兩類節點,一類是管理節點(Namenode),一類是工作節點(Datanode)。而HDFS就是以管理節點-工作節點的模式執行的,在HDFS上,通常有一個Namenode和多個Datanode(一個管理者master,多個工作者slave)。

作為master的NameNode負責管理分散式檔案系統的名稱空間(NameSpace),即維護的是檔案系統樹及樹內的檔案和目錄。這些資訊以 兩個核心檔案(fsImageeditlog)的形式持久化在本地磁碟中。

fsImage名稱空間映象檔案,用於維護檔案系統樹以及檔案樹中所有檔案和目錄的元資料;操作日誌檔案editlog中記錄了所有針對檔案的建立、刪除、重新命名等操作。namenode也記錄了每個檔案的各個塊所在的datanode的位置資訊,但並不持久化儲存這些資訊,而是在系統每次啟動時掃描所datanode重構得到這些資訊,也就是說儲存在執行記憶體中。

作為slave的Datanode是分散式檔案系統HDFS的工作節點,負責資料塊的儲存和讀取(會根據客戶端或者Namenode的排程來進行資料的儲存和檢索),並且定期向Namenode傳送自己所儲存的塊的列表。每個Datanode中的資料會被儲存在本地Linux檔案系統中。

3、SecondaryNamenode

在名稱節點執行期間,HDFS會不斷髮生更新操作,這些更新操作都是直接被寫入到EditLog檔案,因此EditLog檔案也會逐漸變大。在名稱節點執行期間,不斷變大的EditLog檔案通常對於系統性能不會產生顯著影響,但是當名稱節點重啟時,需要將FsImage載入到記憶體中,然後逐條執行EditLog中的記錄,使得FsImage保持最新。可想而知,如果EditLog很大,就會導致整個過程變得非常緩慢,使得名稱節點在啟動過程中長期處於“安全模式”,無法正常對外提供寫操作,影響了使用者的使用。

為了有效解決EditLog檔案逐漸變大帶來的問題,HDFS在設計中採用了第二名稱節點(SecondaryNameNode)。第二名稱節點是HDFS架構的一個重要組成部分,具有兩方面的功能:首先,可以完成EditLog與FsImage的合併操作,減小EditLog檔案大小,縮短名稱節點重啟時間;其次,可以作為名稱節點的“檢查點”,儲存名稱節點中的元資料資訊。具體如下:

(1)EditLog與FsImage的合併操作。每隔一段時間,第二名稱節點會和名稱節點通訊,請求其停止使用EditLog檔案(這裡假設這個時刻為t1),暫時將新到達的寫操作新增到一個新的檔案EditLog.new中。然後,第二名稱節點把名稱節點中的FsImage檔案和EditLog檔案拉回本地,再載入到記憶體中;對二者執行合併操作,即在記憶體中逐條執行EditLog中的操作,使得FsImage保持最新。合併結束後,第二名稱節點會把合併後得到的最新的FsImage檔案傳送到名稱節點。名稱節點收到後,會用最新的FsImage檔案去替換舊的FsImage檔案,同時用EditLog.new去替換EditLog檔案(這裡假設這個時刻為t2),從而減小了EditLog檔案的大小。

(2)作為名稱節點的“檢查點”。從上面的合併過程可以看出,第二名稱節點會定期和名稱節點通訊,從名稱節點獲取FsImage檔案和EditLog檔案,執行合併操作得到新的FsImage檔案。從這個角度來講,第二名稱節點相當於為名稱節點設定了一個“檢查點”,週期性地備份名稱節點中的元資料資訊,當名稱節點發生故障時,就可以用第二名稱節點中記錄的元資料資訊進行系統恢復。但是,在第二名稱節點上合併操作得到的新的FsImage檔案是合併操作發生時(即t1時刻)HDFS記錄的元資料資訊,並沒有包含t1時刻和t2時刻期間發生的更新操作,如果名稱節點在t1時刻和t2時刻期間發生故障,系統就會丟失部分元資料資訊,在HDFS的設計中,也並不支援把系統直接切換到第二名稱節點,因此從這個角度來講,第二名稱節點只是起到了名稱節點的“檢查點”作用,並不能起到“熱備份”作用。即使有了第二名稱節點的存在,當名稱節點發生故障時,系統還是可能會丟失部分元資料資訊的。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

作為slave的Datanode名稱節點在啟動時,會將FsImage的內容載入到記憶體當中,然後執行EditLog檔案中的各項操作,使得記憶體中的元資料保持最新。這個操作完成以後,就會建立一個新的FsImage檔案和一個空的EditLog檔案。名稱節點啟動成功並進入正常執行狀態以後,HDFS中的更新操作都被寫到EditLog,而不是直接寫入FsImage,這是因為對於分散式檔案系統而言,FsImage檔案通常都很龐大,如果所有的更新操作都直接往FsImage檔案中新增,那麼系統就會變得非常緩慢。相對而言,EditLog通常都要遠遠小於FsImage,更新操作寫入到EditLog是非常高效的。名稱節點在啟動的過程中處於“安全模式”,只能對外提供讀操作,無法提供寫操作。在啟動結束後,系統就會退出安全模式,進入正常執行狀態,對外提供寫操作。

 

 

 

 

 

 

 

 

六、副本概念

HDFS上的塊會進行冗餘儲存,也就是副本策略。因為hdfs要執行在廉價的硬體之上,出現故障是正常現象,而為了保證資料的可靠性,資料塊是被複製成多份,當一份資料宕掉後,其餘的可以即刻補上。副本的個數,預設是3。當然可以在hdfs-default.xml中進行修改:

<property>
  <name>dfs.replication</name>
  <value>3</value>
</property>

 那麼,