在前面的文章 《HDFS DataNode 設計實現解析》中咱們對文件操做進行了描述,但並未展開講述其中涉及的異常錯誤處理與恢復機制。本文將深刻探討 HDFS 文件操做涉及的錯誤處理與恢復過程。html
讀文件可能發生的異常有兩種:算法
HDFS 的文件塊多副本分散存儲機制保障了數據存儲的可靠性,對於第一種狀況 DataNode 掛了只須要失敗轉移到其餘副本所在的 DataNode 繼續讀取,而對於第二種狀況讀取到的文件數據塊若校驗失敗可認定爲損壞,依然能夠轉移到讀取其餘無缺的副本,並向 NameNode 彙報該文件 block 損壞,後續處理由 NameNode 通知 DataNode 刪除損壞文件 block,並根據無缺的副原本複製一份新的文件 block 副本。apache
由於讀文件不涉及數據的改變,因此處理起來相對簡單,恢復機制的透明性和易用性都很是好。微信
以前的文章中對寫文件的過程作了描述,這個過程當中可能發生多種不一樣的錯誤異常對應着不一樣的處理方式。先看看有哪些可能的異常?markdown
可能的異常模式以下所列:網絡
對於以上所列的異常模式,都有分別對應的恢復模式。app
當 Client 在寫入過程當中,本身掛了。因爲 Client 在寫文件以前須要向 NameNode 申請該文件的租約(lease),只有持有租約才容許寫入,並且租約須要按期續約。因此當 Client 掛了後租約會超時,HDFS 在超時後會釋放該文件的租約並關閉該文件,避免文件一直被這個掛掉的 Client 獨佔致使其餘人不能寫入。這個過程稱爲 lease recovery。分佈式
在發起 lease recovery 時,若多個文件 block 副本在多個 DataNodes 上處於不一致的狀態,首先須要將其恢復到一致長度的狀態。這個過程稱爲 block recovery。 這個過程只能在 lease recovery 過程當中發起。ide
當 Client 在寫入過程當中,有 DataNode 掛了。寫入過程不會馬上終止(若是馬上終止,易用性和可用性都太不友好),取而代之 HDFS 嘗試從流水線中摘除掛了的 DataNode 並恢復寫入,這個過程稱爲 pipeline recovery。oop
當 Client 在寫入過程當中,NameNode 掛了。這裏的前提是已經開始寫入了,因此 NameNode 已經完成了對 DataNode 的分配,若一開始 NameNode 就掛了,整個 HDFS 是不可用的因此也沒法開始寫入。流水線寫入過程當中,當一個 block 寫完後需向 NameNode 報告其狀態,這時 NameNode 掛了,狀態報告失敗,但不影響 DataNode 的流線工做,數據先被保存下來,但最後一步 Client 寫完向 NameNode 請求關閉文件時會出錯,因爲 NameNode 的單點特性,因此沒法自動恢復,需人工介入恢復。
上面先簡單介紹了對應異常的恢復模式,詳細過程後文再描述。在介紹詳細恢復過程前,須要瞭解文件數據狀態的概念。由於寫文件過程當中異常和恢復會對數據狀態產生影響,咱們知道 HDFS 文件至少由 1 個或多個 block 構成,所以每一個 block 都有其相應的狀態,因爲文件的元數據在 NameNode 中管理而文件數據自己在 DataNode 中管理,爲了區分文件 block 分別在 NameNode 和 DataNode 上下文語境中的區別,下面咱們會用 replica(副本)特指在 DataNode 中的 block,而 block 則限定爲在 NameNode 中的文件塊元數據信息。在這個語義限定下 NameNode 中的 block 實際對應 DataNodes 上的多個 replicas,它們分別有不一樣的數據狀態。咱們先看看 replica 和 block 分別在 DataNode 和 NameNode 中都存在哪些狀態?
Replica 在 DataNode 中存在的狀態列表以下:
DataNode 會持久化存儲 replica 的狀態,每一個數據目錄都包含了三個子目錄:
FINALIZED
狀態 replicas。TEMPORARY
狀態的 replicas。RBW
、RWR
和 RUR
三種狀態的 relicas,從該目錄下加載的 replicas 默認都處於 RWR
狀態。從目錄看出實際上只持久化了三種狀態,而在內存中則有五種狀態,從下面的 replica 狀態變遷圖也能夠看出這點。
咱們從 Init
開始簡單描述下 replica 的狀態變遷圖。
Init
出發,一個新建立的 replica 初始化爲兩種狀態: RBW
。TEMPORARY
。RBW
出發,有三種狀況: FINALIZED
狀態。RWR
狀態,重啓期間數據可能過期了,能夠被丟棄。RUR
狀態。TEMPORARY
出發,有兩種狀況: FINALIZED
狀態。RWR
出發,有兩種狀況: RBW
狀態,由於持久化目錄 rbw
包含了三種狀態,重啓後又回到 RWR
狀態。RUR
狀態。RUR
出發,有兩種狀況: RBW
狀態,重啓後只會回到 RWR
狀態,看是否還有必要參與恢復仍是過期直接被丟棄。FINALIZED
狀態。FINALIZED
出發,有兩種狀況: RBW
。RUR
狀態。接下咱們再看看 NameNode 上 block 的狀態有哪些以及時如何變化的。
Block 在 NameNode 中存在的狀態列表以下:
UNDER_CONSTRUCTION
狀態下 block 在 block recovery 過程開始後會變動爲該狀態。FINALIZED
狀態的 replica 數量少於最小副本數要求。FINALIZED
狀態的 replica 數量達到最小副本數要求後,則切換到該狀態。只有當文件的全部 block 處於該狀態纔可被關閉。NameNode 不會持久化存儲這些狀態,一旦 NameNode 發生重啓,它將全部打開文件的最後一個 block 設置爲 UNDER_CONSTRUCTION
狀態,其餘則所有設置爲 COMPLETE
狀態。
下圖展現了 block 的狀態變化過程。
咱們仍是從 Init
開始簡單描述下 block 的狀態變遷圖。
Init
出發,只有當 Client 新建或追加文件寫入時新建立的 block 處於 UNDER_CONSTRUCTION
狀態。UNDER_CONSTRUCTION
出發,有三種狀況: FINALIZED
狀態的 replica 數量少於最小副本數要求,則切換到 COMMITTED
狀態, FINALIZED
狀態的 replica 數量達到最小副本數要求,則切換到 COMPLETE
狀態UNDER_RECOVERY
。UNDER_RECOVERY
,有三種狀況: COMPLETE
。UNDER_CONSTRUCTION
狀態。COMMITTED
出發,有兩種狀況: FINALIZED
狀態的 replica 數量達到最小副本數要求或者文件被強制關閉或者 NameNode 重啓且不是最後一個 block, COMPLETE
狀態。UNDER_CONSTRUCTION
狀態。COMPLETE
出發,只有在 NameNode 發生重啓,其打開文件的最後一個 block 會恢復成 UNDER_CONSTRUCTION
狀態。 理解了 block 和 replica 的狀態及其變化過程,咱們就能夠進一步詳細分析上述簡要說起的幾種自動恢復模式。
前面講了 lease recovery 的目的是當 Client 在寫入過程當中掛了後,通過必定的超時時間後,收回租約並關閉文件。但在收回租約關閉文件前,須要確保文件 block 的多個副本數據一致(分佈式環境下不少異常狀況均可能致使多個數據節點副本不一致),若不一致就會引入 block recovery 過程進行恢復。下面是整個恢復處理流程的簡要算法描述:
其中 3~6 步就屬於 block recovery 的處理過程,這裏有個疑問爲何在多個副本中選擇最小長度做爲最終更新一致的標準?想一想寫入流水線過程,若是 Client 掛掉致使寫入中斷後,對於流水線上的多個 DataNode 收到的數據在正常狀況下應該是一致的。但在異常狀況下,排在首位的收到的數據理論上最多,末位的最少,因爲數據接收的確認是從末位按反方向傳遞到首位再到 Client 端。因此排在末位的 DataNode 上存儲的數據都是實際已被確認的數據,而它上面的數據實際在不一致的狀況也是最少的,因此算法裏選擇多個節點上最小的數據長度爲標準來同步到一致狀態。
如上圖所示,pipeline 寫入包括三個階段:
FINALIZED
狀態,並向 NameNode 發送 block 報告。NameNode 將根據報告的 FINALIZED
狀態的 replica 數量是否達到最小副本要求來改變相應 block 狀態爲 COMPLETE
。Pipeline recovery 能夠發生在這三個階段中的任意一個,只要在寫入過程當中一個或多個 DataNode 遭遇網絡或自身故障。咱們來分別分析下。
在 pipeline 準備階段發生錯誤,分兩種狀況:
到了 close 階段纔出錯,實際數據已經所有寫入了 DataNodes 中,因此影響很小了。Client 依然根據剩下正常的 DataNode 重建 pipeline,讓剩下的 DataNode 繼續完成 close 階段須要作的工做。
以上就是 pipeline recovery 三個階段的處理過程,這裏還有點小小的細節可說。
當 pipeline 中一個 DataNode 掛了,Client 重建 pipeline 時是能夠移除掛了的 DataNode,也可使用新的 DataNode 來替換。這裏有策略是可配置的,稱爲 DataNode Replacement Policy upon Failure,包括下面幾種狀況:
本文講述了 HDFS 異常處理與恢復的處理流程和細節,它確保 HDFS 在面對網絡和節點錯誤的狀況下保證數據寫入的持久性和一致性。讀完本篇相信你會對 HDFS 內部的一些設計和工做狀態有更深的認識,本文特意抽象的描述了一些涉及具體算法的部分。由於 HDFS 做爲一個開源軟件還在不斷髮展演變,具體算法代碼實現總會變化,但設計理念和 design for failure 的設計思考要點的持續性要長久的多,會更具參考價值。若是你還想對某些特定細節的實現作進一步的瞭解,只能去深刻閱讀對應部分的代碼,這沒法經過閱讀文檔或相關文章來得到,這也是代碼開源的價值所在。
[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
[4] Yongjun Zhang. Understanding HDFS Recovery Processes
[5] Hairong
Kuang,
Konstantin
Shvachko,
Nicholas
Sze,
Sanjay
Radia,
Robert
Chansler
, Yahoo!
HDFS
team
Design Specification: Append/Hflush/Read
Design
[6] HDFSteam. Design Specification: HDFS Append and Truncates
下面是我本身開的一個微信公衆號 [瞬息之間],除了寫技術的文章、還有產品的、行業和人生的思考,但願能和更多走在這條路上同行者交流,有興趣可關注一下,謝謝。