1.HDFS簡介
正如其名,HDFS(Hadoop Distribution File System)
是一個分布式文件系統,它在商用服務器集群中存儲文件,用來存儲和快速訪問大文件與大數據集。這是一個可擴展、可容錯的系統。
HDFS
的優點:
- 兼容廉價的硬件設備
- 流數據讀寫
- 大數據集
- 簡單的文件模型
- 強大的跨平臺模型
HDFS
的局限性:
- 不適合低延遲數據訪問
- 無法高效存儲大量小文件
- 不支持多用戶寫入及任意修改文件
2.HDFS相關概念
2.1 塊結構
HDFS
是一個塊結構的文件系統。正像Linux文件系統那樣,HDFS
把文件分成固定大小的塊通常叫做分塊或者分片,每個快作為獨立的單元進行存儲。默認的塊大小為64MB,但是可以配置。我們所熟悉的普通文件系統的塊一般只有幾千字節,從這個塊的大小清楚的看到,HDFS
不是用來存儲小文件的,這樣做的好處就是最小化尋址開銷。HDFS
采用抽象的塊概念可以帶來以下幾個明顯的好處:
- 支持大規模文件存儲:文件以塊為單位進行存儲,一個大規模文件可以被分拆成若干個文件塊,不同的文件塊可以被分發到不同的節點上,因此,一個文件的大小不會受到單個節點的存儲容量的限制,可以遠遠大于網絡中任意節點的存儲容量。
- 簡化系統設計:首先,大大簡化了存儲管理,因為文件塊大小是固定的,這樣就可以很容易計算出一個節點可以存儲多少文件塊;其次,方便了元數據的管理,元數據不需要和文件塊一起存儲,可以由其他系統負責管理元數據。
- 適合數據備份:每個文件塊都可以冗余存儲到多個節點上,大大提高了系統的容錯性和可用性。
2.2 HDFS主要組件的功能
一個HDFS集群包含兩種類型的節點:NameNode
和DataNode
。
NameNode | DataNode |
---|---|
存儲元數據 | 存儲文件內容 |
元數據保存在內存中 | 文件內容保存在磁盤 |
保存文件,block,datanode之間的映射關系 | 維護了block id到datanode本地文件的映射關系 |
NameNode
周期性接收來自HDFS
集群中DataNode
的兩種類型的消息,分別叫做心跳消息和塊報告消息。DataNode
發送一個心跳消息來告知NameNode
工作正常。塊報告消息包含一個DataNode
上所有數據塊的列表。
2.3名稱節點 NameNode
?在HDFS中,名稱節點(NameNode
)負責管理分布式文件系統的命名空間(Namespace
),保存了兩個核心的數據結構,即FsImage
和EditLog
。
- ?
FsImage
用于維護文件系統樹以及文件樹中所有的文件和文件夾的元數據。 - ?操作日志文件
EditLog
中記錄了所有針對文件的創建、刪除、重命名等操作。
NameNode
記錄了每個文件中各個塊所在數據節點的位置信息。
FSImage文件
FsImage
文件包含文件系統中所有目錄和文件inode的序列化形式。每個inode
是一個文件或目錄的元數據的內部表示,并包含此類信息:文件的復制等級、修改和訪問時間、訪問權限、塊大小以及組成文件的塊。對于目錄,則存儲修改時間、權限和配額元數據。
FsImage
文件沒有記錄文件包含哪些塊以及每個塊存儲在哪個數據節點。而是由名稱節點把這些映射信息保留在內存中,當數據節點加入HDFS
集群時,數據節點會把自己所包含的塊列表告知給名稱節點,此后會定期執行這種告知操作,以確保名稱節點的塊映射是最新的。
NameNode的啟動
在名稱節點啟動的時候,它會將FsImage
文件中的內容加載到內存中,之后再執行EditLog
文件中的各項操作,使得內存中的元數據和實際的同步,存在內存中的元數據支持客戶端的讀操作。
一旦在內存中成功建立文件系統元數據的映射,則創建一個新的FsImage
文件和一個空的EditLog
文件。
名稱節點起來之后,HDFS
中的更新操作會重新寫到EditLog
文件中,因為FsImage
文件一般都很大(GB級別的很常見),如果所有的更新操作都往FsImage
文件中添加,這樣會導致系統運行的十分緩慢,但是,如果往EditLog
文件里面寫就不會這樣,因為EditLog
要小很多。每次執行寫操作之后,且在向客戶端發送成功代碼之前,edits
文件都需要同步更新。
2.4 數據節點DataNode
數據節點(DataNode
)是分布式文件系統HDFS的工作節點,負責數據的存儲和讀取,會根據客戶端或者名稱節點的調度來進行數據的存儲和檢索,并且向名稱節點定期發送自己所存儲的塊列表。每個數據節點中的數據會保存在各自節點的本地Linux文件系統中。下面圖是數據節點的存儲目錄:
- current目錄:保存著HDFS文件系統中的數據塊,這些數據塊是成功提交到HDFS的數據塊。
- in_use.lock:表明目錄已經被使用,停止數據節點,該文件會消失,通過in_use.lock文件,數據節點可以保證獨自占用該目錄,防止兩個數據節點示例共享一個目錄,造成混亂。
2.5 第二名稱節點SecondaryNameNode
NameNode
運行期間EditLog
不斷變大的問題?
在NameNode
運行期間,HDFS
的所有更新操作都是直接寫到EditLog
中,久而久之,EditLog
文件將變得很大。雖然這對名稱節點運行時候是沒有什么明顯影響的,但是,當名稱節點重啟的時候,名稱節點需要先將FsImage
里面的所有內容映像到內存中,然后再一條一條地執行EditLog
中的記錄,當EditLog
文件非常大的時候,會導致名稱節點啟動操作非常慢,而在這段時間內HDFS系統處于安全模式,一直無法對外提供寫操作,影響了用戶的使用。
為了有效解決EditLog
逐漸變大帶來的問題,HDFS提供的解決方案是SecondaryNameNode
第二名稱節點,并且具有兩個功能:
- 1、可以完成
Editlog
與FsImage
的合并操作,減少Editlog
文件大小,縮短名稱節點重啟時間; - 2、可以作為名稱節點的“檢查點”,保存名稱節點中的元數據信息。
SecondaryNameNode
一般是單獨運行在一臺機器上(Master)。
SecondaryNameNode的工作情況:
- 1、
SecondaryNameNode
會定期和NameNode
通信,請求其停止使用EditLog
文件,暫時將新的寫操作寫到一個新的文件edit.new上來,這個操作是瞬間完成,上層寫日志的函數完全感覺不到差別; - 2、
SecondaryNameNode
通過HTTP GET
方式從NameNode
上獲取到FsImage
和EditLog
文件,并下載到本地的相應目錄下; - 3、
SecondaryNameNode
將下載下來的FsImage
載入到內存,然后一條一條地執行EditLog
文件中的各項更新操作,使得內存中的FsImage
保持最新;這個過程就是EditLog
和FsImage
文件合并; - 4、
SecondaryNameNode
執行完(3)操作之后,會通過post
方式將新的FsImage
文件發送到NameNode
節點上; - 5、
NameNode
將從SecondaryNameNode
接收到的新的FsImage
替換舊的FsImage
文件,同時將edit.new
替換EditLog
文件,通過這個過程EditLog
就變小了。
3.HDFS體系結構
HDFS采用了主從(Master/Slave)結構模型,一個HDFS集群包括一個名稱節點和若干個數據節點。名稱節點作為中心服務器,負責管理文件系統的命名空間及客戶端對文件的訪問。集群中的數據節點一般是一個節點運行一個數據節點進程,負責處理文件系統客戶端的讀取請求,在名稱節點的統一調度下進行數據塊的創建、刪除和復制等操作。每個數據節點的數據實際上保存在本地Linux文件系統中的。每個數據節點會周期性向名稱節點發送“心跳”信息,報告自己的狀態,沒有按時發送心跳信息的數據節點會被標記為“宕機”,不會再給它分配任何IO請求。
HDFS是一個部署在集群上的分布式文件系統,因此,很多數據需要通過網絡進行傳輸。所有的HDFS通信協議都是構建在TCP/IP
協議基礎之上的。
- 客戶端通過一個可配置的端口向名稱節點主動發起TCP連接,并使用客戶端協議與名稱節點進行交互。
- 名稱節點和數據節點之間則使用數據節點協議進行交互。
- 客戶端與數據節點的交互是通過RPC(Remote Procedure Call)來實現的。在設計上,名稱節點不會主動發起RPC,而是響應來自客戶端和數據節點的RPC請求。
4. HDFS存儲原理
4.1 冗余數據保存
作為一個分布式文件系統,為了保證系統的容錯性和可用性,HDFS采用了多副本方式對數據進行冗余存儲,通常一個數據塊的多個副本會被分布到不同的數據節點上。這種多副本方式具有以下幾個優點:
- 1、加快數據傳輸速度
- 2、容易檢查數據錯誤
- 3、保證數據可靠性
例如,數據塊1被分別存放到數據節點A和C,數據塊2被存放在數據節點A和B上。
4.2 數據存取策略
4.2.1 數據存放
為了提高數據的可靠性與系統的可用性,以及充分利用網絡帶寬,HDFS采用了以機架(RACK)為基礎的數據存放策略。HDFS默認每個數據節點都是在不用的機架上,這種方法會存在一個缺點:
- 在寫入數據的時候不能充分利用同一個機架內部機器之間的帶寬。(同一個機架中的不同機器之間的通信要比不同機架之間機器的通信帶寬大)
但是和這種缺點相比,也有很多顯著的優點:
- 1、可以獲得很高的數據可靠性,即使一個機架發生故障,位于其他機架上的數據副本仍然是可以用的;
- 2、在讀取數據的時候,可以在多個機架上并行讀取數據,大大提高了數據讀取速度;
- 3、可以更容易地實現系統內部負載均衡和錯誤處理。
問題:什么叫做機架(RACK)?
HDFS默認的冗余復制因子是3,每個文件塊會被同時保存到3個地方,其中有兩份副本放在同一個機架的不同機器上面,第三個副本放在不同機架的機器上面,這樣既可以保證機架發生異常時的數據恢復,也可以提高讀寫性能。一般而言,HDFS副本的放置策略如下圖:
4.2.2 數據讀取
HDFS提供了一個API可以確定一個數據節點所屬的機架ID,客戶端也可以調用API獲取自己所屬的機架ID。當客戶端讀取數據時,從名稱節點獲得數據塊不同副本的存放位置列表,列表中包含了副本所在的數據節點,可以調用API來確定客戶端和這些數據節點所屬的機架ID,當發現某個數據塊副本對應的機架ID和客戶端對應的機架ID相同時,就優先選擇該副本讀取數據,如果沒有發現,就隨機選擇一個副本讀取數據。
4.2.3 數據復制
HDFS的數據復制采用流水線復制的策略,大大提高了數據復制過程的效率。
- 1、當客戶端要往HDFS中寫入一個文件時,這個文件會首先被寫入本地,并被切分若干個塊,每個塊的大小是由HDFS的設定值來決定的。
- 2、每個塊都向HDFS集群中的名稱節點發起寫請求,名稱節點會根據系統中各個數據節點的使用情況,選擇一個數據節點列表返回給客戶端。
- 3、然后客戶端就把數據首先寫入列表中的第一個數據節點,同時把列表傳給第一個數據節點。當第一個數據節點接收到4KB的數據的時候,寫入本地,并且向列表中的第二個數據節點發起連接請求;
- 4、當第二個數據節點接收到4KB數據的時候,寫入本地,并且向列表中的第三個數據節點發起連接請求;
- 5、依次類推,列表中的多個數據節點形成一條數據復制的流水線。最后,當文件寫完的時候,數據復制也同時完成。
4.3 數據錯誤與恢復
4.3.1 名稱節點出錯
名稱節點保存了所有的元數據信息,其中,最核心的兩個數據結構是FSImage
和Editlog
,如果這兩個文件發生損壞,那么整個HDFS實例將失效。因此,HDFS設置了備份機制,把這些核心文件同步復制到備份服務器SecondaryNameNode
上。當名稱節點出錯時,就可以根據備份服務器SecondaryNameNode
中FSImage
和Editlog
數據進行恢復。
4.3.2 數據節點出錯
每個數據節點定期會向名稱節點發送“心跳”信息,向名稱節點報告自己的狀態。當數據節點發生故障,或者網絡發生斷網時,名稱節點就無法收到來自一些數據節點的心跳信息,這時,這些數據節點就會被標記為“宕機”,節點上面的所有書都會被標記為“不可讀”,名稱節點不會給它們發送任何IO請求。
4.3.3 數據出錯
網絡傳輸和磁盤錯誤等因素會造成數據錯誤。客戶端在讀取數據后,會采用MD5
和SHA1
對數據塊進行校驗,以確定讀取到正確的數據。
- 1、在文件被創建時,客戶端就會對每個文件塊進行信息摘錄,并把這些信息寫入同一個路徑的隱藏文件里面;
- 2、當客戶端讀取文件的時候,會先讀取該信息文件,然后利用該信息文件對每個讀取的數據塊進行校驗;
- 3、如果校驗出錯,客戶端就會請求到另外一個數據節點讀取該文件塊,并且向名稱節點報告這個文件塊有錯誤,名稱節點會定期檢查并且重新復制這個塊。
5. HDFS數據讀寫過程
5.1 讀取
當一個客戶端應用想要讀取一個文件時,它首先訪問NameNode
。NameNode
以組成文件的所有文件塊的位置來響應。塊的位置標識了持有對應文件塊數據的DataNode
。客戶端緊接著直接向DataNode發送讀請求,以獲取每個文件塊。NameNode
不參與從DataNode
到客戶端的實際數據傳輸過程。
5.2 寫入
當客戶端應用想要寫數據到HDFS文件時,它首先訪問NameNode并要求它在HDFS命名空間中創建一個新的條目。NameNode會檢查同名文件是否已存在以及客戶端是否有權限來創建新文件。
- 接下來,客戶端應用請求NameNode為文件的第一個塊選擇DataNode。它會在所持有塊的復制節點之間創建一個管道,并把數據塊發送到管道中第一個DataNode。
- 第一個DataNode在本地存儲數據塊,然后把它轉發給第二個DataNode。第二個DataNode也在本地存儲相應數據塊,并把它裝發給第三個DataNode。
- 在所有委派的DataNode上都存儲第一個文件塊之后,客戶端請求NameNode為第二個塊分配DataNode。這個過程持續進行,直到所有文件塊都已經在DataNode上存儲。最后,客戶端告知NameNode文件寫操作已完成。
參考資料
http://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html