HDFS DataNode 设计实现解析
前文分析了 NameNode,本文進一步解析 DataNode 的設計和實現要點。
文件存儲
DataNode 正如其名是負責存儲文件數據的節點。HDFS 中文件的存儲方式是將文件按塊(block)切分,默認一個 block 64MB(該大小可配置)。若文件大小超過一個 block 的容量可能會被切分為多個 block,并存儲在不同的 DataNode 上。若文件大小小于一個 block 的容量,則文件只有一個 block,實際占用的存儲空間為文件大小容量加上一點額外的校驗數據。也可以這么說一個文件至少由一個或多個 block 組成,而一個 block 僅屬于一個文件。
block 是一個邏輯概念對象,由 DataNode 基于本地文件系統來實現。每個 block 在本地文件系統中由兩個文件組成,第一個文件包含文件數據本身,第二個文件則記錄 block 的元信息(metadata)如:數據校驗和(checksum)。所以每一個 block 對象實際物理對應兩個文件,但 DataNode 不會將文件創建在同一個目錄下。因為本機文件系統可能不能高效的支持單目錄下的大量文件,DataNode 會使用啟發式方法決定單個目錄下存放多少文件合適并在適當時候創建子目錄。
文件數據存儲的可靠性依賴多副本保障,對于單一 DataNode 節點而言只需保證自己存儲的 block 是完整且無損壞的。DataNode 會主動周期性的運行一個 block 掃描器(scanner)通過比對 checksum 來檢查 block 是否損壞。另外還有一種被動的檢查方式,就是當讀取時檢查。
文件操作
HDFS 支持的文件操作包括寫入(新增、追加)、讀取和刪除。HDFS 定義了一種 multi-reader, single-writer 的文件訪問語義。而訪問標準依然參照大家熟悉的依據 POSIX(Portable Operating System Interface)為單機文件系統定義的 API。
- Open 打開文件
- Read/Write 讀寫文件
- Close 關閉文件
下面我們分別講述文件操作的設計實現要點。
寫文件
寫文件流程如圖示,在分布式環境下,Client 請求 NameNode 獲得一個針對指定文件的租約(lease,本質上是一種分布式鎖,詳細請自行維基百科下)。只有持有該租約的 Client 可以向該文件寫入,以這種機制來確保寫文件的 single-writer 的語義。獲得寫入租約后 NameNode 向 Client 分配一組用于存放文件數據的 DataNodes,若配置的副本數為 3,則會返回 3 個 DataNode。這一組 DataNodes 被組成一條流水線來寫入,有效提升寫入性能降低寫入延遲。Client 將文件組織成一個個 packet 發送給流水線上第一個 DataNode,第一個 DataNode 存儲下該 packet 后再轉發給第二個 DataNode,依此類推。然后 DataNodes 再按流水線反方向發回確認 packet 給 Client。當所有文件 block 寫入完成后,DataNodes 會向 NameNode 報告文件的 block 接收完畢,NameNode 相應去改變文件元數據的狀態。
寫文件的主體流程如上所述,如果過程中一切正常那么多么簡單美好。但實際在分布式環境下,寫文件過程涉及 Client、NameNode 和一組 DataNodes,這其中任何一個環節都有可能產生異常。按照分布式設計第一原則:Design for failure,我們需要考這個流程中的所有參與者都有可能出現失敗異常的情況。這里先提出這個問題,考慮每種失敗異常的場景下,軟件設計實現要怎么去處理?本文先不在這里展開論述,后面會專門撰文深入分析。
讀文件
讀文件流程如圖示,Client 首先請求 NameNode 定位文件 block 所在的 DataNodes。然后按順序請求對應的 DataNodes 讀取其上存儲的 block。關于讀取順序,HDFS 有一個就近讀取的優化策略,DataNodes 的讀取排序會按照它們離 Client 的距離來確定。距離的概念主要區分以下幾種場景:
- 距離 0,表示在同一個節點上
- 距離 2,表示同一個機架下的不同節點
- 距離 4,表示同一個數據中心的不同機架下
- 距離 8,表示不同的數據中心
刪文件
文件刪除的處理首先將文件重命名后放進 /trash 目錄。文件會在 /trash 目錄中存放一段時間(可配置),在時間到期后再自動清理。所以實際上文件刪除操作非常輕量級,僅僅是 NameNode 的內存數據結構的變動,真正的物理刪除在后續的自動清理時才做。
可見性
在文件寫入過程中,HDFS 不保證文件對其他 Client Reader 可見。只有文件的 block 已經寫入 DataNode,并報告給了 NameNode 更新到正確的狀態才對其他 Reader 可見。簡單說,如果一個文件有多個 block,寫入總是發生在最后一個 block 上,那么前面的 block 對其他 Reader 是可見的,但最后一個 block 則不可見,這涉及 block 的狀態變化,這里先不展開,后面會專門撰文深入分析。
生命周期
DataNode 啟動后首先連接到 NameNode 完成握手,握手的目的是驗證 DataNode 的軟件版本和 namespace ID。namespace ID 是整個 HDFS 集群的唯一標識,如果 DataNode namespace ID 或 軟件版本與 NameNode 不匹配,DataNode 將無法加入集群并自動關閉。若是一個全新的 DataNode 啟動時沒有 namespace ID,則在握手時由 NameNode 分配并加入集群。此外,NameNode 還會分配一個集群全局唯一的 storage ID 給 DataNode 用于唯一標記,之后不再改變。
完成握手后,DataNode 會立刻向 NameNode 發送 block report 信息,block report 就是 DataNode 上存儲了哪些文件 block 的列表。之后會定期(默認 1 小時)向 NameNode 報告。此外,DataNode 將定時向 NameNode 發送心跳(默認 3 秒)來報告自身的存活性。一段時間(默認 10 分鐘)收不到 DataNode 最近的心跳,NameNode 會認定其死亡,并不會再將 I/O 請求轉發到其上。心跳除了用于 DataNode 報告其存活性,NameNode 也通過心跳回復來捎帶控制命令要求 DataNode 執行,因為 NameNode 設計上不直接調用 DataNode 其控制命令都是通過心跳回復來執行,所以心跳的默認間隔比較短。
除了 DataNode 的非正常死亡外,DataNode 還可以正常退休,可以通過管理端標記一個 DataNode 進入退休中(decommissioning)狀態。處于退休中狀態的 DataNode 不再服務于寫請求(包括從 Client 寫入或從其他 DataNode 復制),但它可以繼續服務讀請求。進入退休中狀態的 DataNode 將被安排將其上存儲的所有 block 復制到其他節點,完成這個過程后 NameNode 將其標記為已退休(decommissioned)狀態,然后就可以安全下線了。
總結
本文重點描述了,DataNode 生命周期對 HDFS 集群整體的影響以及文件訪問操作的流程。對于異常處理部分沒有詳細展開講述,這個系列的后續文章還會進一步深入剖析。
參考
[1] Hadoop Documentation. HDFS Architecture.
[2] Robert Chansler, Hairong Kuang, Sanjay Radia, Konstantin Shvachko, and Suresh Srinivas. The Hadoop Distributed File System
[3] Tom White. Hadoop: The Definitive Guide. O’Reilly Media(2012-05), pp 94-96
下面是我自己開的一個微信公眾號 [瞬息之間],除了寫技術的文章、還有產品的、行業和人生的思考,希望能和更多走在這條路上同行者交流,有興趣可關注一下,謝謝。
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
?
轉載于:https://www.cnblogs.com/mindwind/p/4833100.html
總結
以上是生活随笔為你收集整理的HDFS DataNode 设计实现解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 读《白帽子讲Web安全》之客户端脚本安全
- 下一篇: 在线批量压缩JPG图片-JpegMini