大數據技術原理與應用——分佈式文件系統HDFS

分佈式文件系統概述

  相對於傳統的本地文件系統而言,分佈式文件系統(Distribute File System)是一種經過網絡實現文件在多臺主機上進行分佈式存儲的文件系統。分佈式文件系統的設計通常採用「客戶/服務機」模式,客戶端以特定的通訊協議經過網絡與服務器創建鏈接,提出文件訪問請求,客戶端和服務器能夠經過設置訪問權限來限制請求方對底層數據存儲塊的訪問。編程

  目前,已經獲得普遍應用的分佈式文件系統主要包括GFS和HDFS等,後者是針對前者的開源實現。緩存


計算機集羣結構

  普通的文件系統只須要單個計算機節點就能夠完成文件的存儲和處理,單個計算機節點由處理器、內存、高速緩存和本地磁盤構成。安全

  分佈式文件系統把文件分佈存儲到多個計算機節點上,成千上萬的計算機節點構成計算機集羣。與以前使用多個處理器和專用高級硬件的並行化處理裝置不一樣的是,目前分佈式文件系統所採用的計算機集羣都是由普通硬件構成的,這就大大下降了硬件上的開銷。服務器

  集羣中的計算機節點存放在機架(Rack)上,每一個機架能夠存放8~64個節點,同一個機架上的不一樣節點之間經過網絡互連(常採用吉比特以太網),多個不一樣機架之間採用另外一級網絡或交換機互連。網絡


 分佈式文件系統的結構  

  在咱們熟悉的Windows、Linux等操做系統中,文件系統通常會把磁盤空間劃分爲512字節一組,稱爲「磁盤塊」,它是文件系統讀寫操做的最小單位,文件系統的塊(Block)一般是磁盤塊的整數倍,即每次讀寫的數據必須是磁盤塊大小的整數倍。數據結構

  與普通文件系統相似,分佈式文件系統也採用了塊的概念,文件被分紅若干個塊進行存儲,塊是數據讀寫的基本單元,只不過度布式文件系統的塊要比操做系統中的塊大不少。好比,HDFS默認的一個塊大小是64MB。與普通文件系統不一樣的是,在分佈式文件系統中,若是一個文件小於一個數據塊的大小,它並不佔用整個數據塊的存儲空間。架構

  分佈式文件系統在物理結構上是由計算機集羣中的多個節點構成的,這些節點分爲兩類:一類叫「主節點」(Master Node),或者也被稱爲「名稱節點」(NameNode);另外一類叫「從節點」(Slave Node),或者也被稱爲「數據節點」(DataNode)。名稱節點負責文件和目錄的建立、刪除和重命名等,同時管理着數據節點和文件塊之間的映射關係,所以客戶端只有訪問名稱節點才能找到請求的文件塊所在的位置,進而到相應的位置讀取所需文件塊。數據節點負責數據的存儲和讀取,在存儲時,由名稱節點分配存儲位置,而後由客戶端把數據直接寫入相應數據節點;在讀取時,客戶端從名稱節點得到數據節點和文件塊的映射關係,而後就能夠到響應位置訪問文件塊。數據節點也要根據名稱節點的命令建立、刪除數據塊和冗餘複製。併發

  計算機集羣中的節點可能會發生故障,所以爲了保證數據的完整性,分佈式文件系統一般會採用多副本存儲。文件塊會被複製爲多個副本,存儲在不一樣的節點上,並且存儲同一文件塊的不一樣副本的各個節點會分佈在不一樣的機架上,這樣,在單個節點出現故障時,就能夠快速調用副本重啓單個節點上的計算過程,而不用重啓整個計算過程,整個機架出現故障時也不會丟失全部文件塊。文件塊的大小和副本個數一般能夠由用戶指定。負載均衡

  分佈式文件系統是針對大規模數據存儲而設計的,主要用於處理大規模文件,如TB級文件。處理太小的文件不只沒法充分發揮其優點,並且會嚴重影響到系統的擴展和功能。分佈式


HDFS簡介 

  HDFS開源實現了GFS的基本思想。和MapReduce一塊兒成爲Hadoop的核心組成部分。HDFS支持流數據讀取和超大規模文件,並可以運行在廉價的普通計算機組成的集羣上,這主要得益於HDFS在設計之初就充分考慮了實際應用環境的特色,那就是,硬件出錯在普通服務器集羣中是一種常態,而不是異常。所以,HDFS在設計上採起了多種機制保證在硬件出錯的環境中實現數據的完整性。整體而言,HDFS要實現如下目標:

  (1)兼容廉價的硬件設備

  (2)流數據讀寫

  (3)大數據集

  (4)簡單的文件模型

  (5)強大的跨平臺兼容性

  HDFS特殊的設計,在實現上述優良特性的同時,也是的自身具備一些應用侷限性,主要包括如下幾個方面:

  (1)不適合低延遲數據訪問

  (2)沒法高效存儲大量小文件

  (3)不支持多用戶寫入及任意修改文件


 HDFS的相關概念

  塊

  在傳統的文件系統中,爲了提升磁盤讀寫效率,通常以數據塊爲單位,而不是以字節爲單位。好比,機械式硬盤(磁盤的一種)包含了磁頭和轉動部件,在讀取數據時有一個尋道的過程,經過轉動盤片和移動磁頭的位置,來找到數據在機械式硬盤中額存儲位置,而後才能進行讀寫。在I/O開銷中,機械式硬盤的尋址時間是最耗時的部分,一旦找到第一條記錄,剩下的順序讀取效率是很是高的。所以,以塊爲單位寫數據,能夠把磁盤尋道時間分攤到大量數據中。

  HDFS也一樣採用了塊的概念,默認一個塊大小是64MB。在HDFS中的文件會被拆分紅多個塊,每一個塊做爲獨立的單元進行存儲。咱們所熟悉的普通文件系統的一個塊通常只有幾千字節,能夠看出,HDFS在塊的大小的設計上明顯要大於普通文件系統。HDFS這麼作的緣由,是爲了最小化尋址開銷。HDFS尋址開銷不只包括磁盤尋道開銷,還包括數據塊的定位開銷。當客戶端須要訪問一個文件時,首先從名稱節點得到組成這個文件的數據塊的位置列表,而後根據位置列表獲取實際存儲各個數據塊的數據節點的位置,最後數據節點根據數據塊信息在本地Linux文件系統中找到對應的文件,並把數據返回給客戶端。設計一個比較大的塊,能夠把上述尋址開銷分攤到較多的數據中,下降了單位尋址的開銷。所以,HDFS在文件塊大小的設置上要遠遠大於普通文件系統,以期在處理大規模文件時可以得到更好地性能。固然,塊的大小也不宜設置過大,由於,一般MapReduce中的Map任務一次只處理一個塊中的數據,若是啓動的任務太少,就會下降做業並行處理速度。

   HDFS採用抽象的塊的概念能夠帶來如下幾個明顯的好處。

  (1)支持大規模文件存儲。文件以塊爲單位進行存儲,一個大規模文件能夠被拆分紅若干個文件塊,不一樣的文件塊能夠被分發到不一樣的節點上,所以一個文件的大小不會受到單個節點的存儲容量的限制,能夠遠遠大於網絡中任意節點的存儲容量。

  (2)簡化系統設計。首先,大大簡化了存儲管理,由於文件塊大小是固定的,這樣就能夠很容易計算出一個節點能夠存出多少文件塊;其次,方便了元數據的管理,元數據不須要和文件塊一塊兒存儲,能夠由其餘系統負責管理元數據。

  (3)適合數據備份。每一個文件塊均可以冗餘存儲到多個節點上,大大提升了系統的容錯性和可用性。

  名稱節點和數據節點

  在HDFS中,名稱節點(NameNode)負責管理分佈式文件系統的命名空間(NameSpace),保存了兩個核心的數據結構,即FsImage和EditLog,FsImage用於維護文件系統樹以及文件樹中全部文件和文件夾的元數據,操做日誌文件EditLog中記錄了全部針對文件的建立、刪除、重命名等操做。名稱節點記錄了每一個文件中各個塊所在的節點的位置信息,可是並不持久化存儲這些信息,而是在系統每次啓動時掃描全部數據節點重構獲得這些信息。

  名稱節點在啓動時,會將FsImage的內容加載到內存當中,而後執行EditLog文件中的各項操做,使得內存中的元數據保持最新。這個操做完成之後,就會建立一個新的FsImage文件和一個空的EditLog文件。名稱節點啓動成功並進入正常運行狀態之後,HDFS中的更新操做都被寫到EditLog,而不是直接寫入FsImage,這是由於對於分佈式文件系統而言,FsImage文件一般都很龐大,若是全部的更新操做都直接往FsImage文件中添加,那麼系統就會變得很是緩慢。相對而言,EditLog一般都要遠遠小於FsImage,更新操做寫入到EditLog是很是高效的。名稱節點在啓動的過程當中處於「安全模式」,只能對外提供讀操做,沒法提供寫操做。在啓動結束後,系統就會退出安全模式,進入正常運行狀態,對外提供寫操做。

  數據節點(DataNode)是分佈式文件系統HDFS的工做節點,負責數據的存儲和讀取,會根據客戶端或者名稱節點的調度來進行數據的存儲和檢索,而且向名稱節點按期發送本身所存儲的塊的列表。每一個數據節點中的數據會被保存在各自節點的本地Linux文件系統中。

  第二名稱節點

  在名稱節點運行期間,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的設計中,也並不支持把系統直接切換到第二名稱節點,所以從這個角度來說,第二名稱節點只是起到了名稱節點的「檢查點」做用,並不能起到「熱備份」做用。即便有了第二名稱節點的存在,當名稱節點發生故障時,系統仍是可能會丟失部分元數據信息的。


HDFS體系結構

  HDFS採用了主從(Master/Slave)結構模型,一個HDFS集羣包括一個名稱節點和若干數據節點。名稱節點做爲中心服務器,負責管理文件系統的命名空間及客戶端對文件的訪問。集羣中的數據節點通常是一個節點運行一個數據節點進程,負責處理文件系統客戶端的讀寫請求,在名稱節點的統一調度下進行數據塊的建立、刪除和複製等操做。每一個數據節點的數據其實是保存在本地Linux文件系統中的。每一個數據節點會週期性地向名稱節點發送「心跳」信息,報告本身的狀態,沒有按時發送心跳信息的數據節點會被標記爲「宕機」,不會再給它分配任何I/O請求。

  用戶在實際使用HDFS時,仍然能夠像在普通文件系統中那樣,使用文件名去存儲和訪問文件。實際上,在系統內部,一個文件會被切分紅若干個數據塊,這些數據塊被分佈存儲到若干個數據節點上。當客戶端須要訪問一個文件時,首先把文件名發送給名稱節點,名稱節點根據文件名找到對應的數據塊(一個文件名可能包括多個數據塊),再根據每一個數據塊信息找到實際存儲各個數據塊的數據節點的位置,並把數據節點位置發送給客戶端,最後客戶端直接訪問這些數據節點獲取數據。在整個訪問過程當中,名稱節點並不參與數據的傳輸。這種設計方式,使得一個文件的數據可以在不一樣的數據節點上實現併發訪問,大大提升了數據訪問速度。

  HDFS採用Java語言開發,所以任何支持JVM的機器均可以部署名稱節點和數據節點。在實際部署時,一般在集羣中選擇一臺性能較好地機器做爲名稱節點,其餘機器做爲數據節點。固然,一臺機器能夠運行任意多個數據節點,甚至名稱節點和數據節點也能夠放在一臺機器上運行,不過,不多在正式部署中採用這種模式。HDFS集羣中只有惟一一個名稱節點,該節點負責全部元數據的管理,這種設計大大簡化了分佈式文件系統的結構,能夠保證數據不會脫離名稱節點的控制,同時,用戶數據永遠不會通過名稱節點,這大大減輕了中心服務器的負擔,方便了數據管理。

  HDFS命名空間管理

  HDFS的命名空間包含目錄、文件和塊。命名空間管理是指命名空間支持對HDFS中的目錄、文件和塊作相似文件系統的建立、修改、刪除等基本操做。在當前的HDFS體系結構中,在整個HDFS集羣中只有一個命名空間,而且只有惟一一個名稱節點,該節點負責對這個命名空間進行管理。

  HDFS使用的是傳統的分級文件體系,所以用戶能夠像使用普通文件系統同樣,建立、刪除目錄和文件,在目錄間轉移文件、重命名文件等。可是,HDFS尚未實現磁盤配額和文件訪問權限等功能,也不支持文件的硬鏈接和軟鏈接(快捷方式)。

  通訊協議

  HDFS是一個部署在集羣上的分佈式文件系統,所以不少數據須要經過網絡進行傳輸。全部的HDFS通訊協議都是構建在TCP/IP協議基礎上的。客戶端經過一個可配置的端口向名稱節點主動發起TCP鏈接,並使用客戶端協議與名稱節點進行交互。名稱節點和數據節點之間則使用數據節點協議進行交互。客戶端與數據節點的交互是經過RPC來實現的。在設計上,名稱節點不會主動發起RPC,而是響應來自客戶端和數據節點的RPC請求。

  客戶端

  客戶端是用戶操做HDFS最經常使用的方式,HDFS在部署時都提供了客戶端。不過須要說明的是,嚴格來講,客戶端並不算是HDFS的一部分。客戶端能夠支持打開、讀取、寫入等常見的操做,而且提供了相似Shell的命令行方式來訪問HDFS中的數據。此外,HDFS也提供了JavaAPI,做爲應用程序訪問文件系統的客戶端編程接口。

  HDFS體系結構的侷限性

  HDFS只設置惟一一個名稱節點,這樣作雖然大大簡化了系統設計,但也帶來了一些明顯的侷限性,具體以下。

  (1)命名空間的限制。名稱節點是保存在內存中的,所以名稱節點可以容納對象(文件、塊)的個數會受到內存空間大小的限制。

  (2)性能的瓶頸。整個分佈式文件系統的吞吐量受限於單個名稱節點的吞吐量。

  (3)隔離問題。因爲集羣中只有一個名稱節點,只有一個命名空間,所以沒法對不一樣的應用程序進行隔離。

  (4)集羣的可用性。一旦這個惟一的名稱節點發生故障,會致使整個集羣變得不可用。


 

HDFS的存儲原理

  數據的冗餘存儲

  做爲一個分佈式文件系統,爲了保證系統的容錯性和可用性,HDFS採用了多副本方式對數據進行冗餘存儲,一般一個數據塊的多個副本會被分佈到不一樣的數據結點上。這種多副本的方式具備如下3個優勢。

  (1)加快數據傳輸速度。當多個客戶端須要同時訪問一個文件時,可讓各個客戶端分別從不一樣的數據副本中讀取數據,這就大大加快了數據傳輸速度。

  (2)容易檢查數據錯誤。HDFS的數據節點之間經過網絡傳輸數據,採用多個副本能夠很容易判斷數據傳輸是否出錯。

  (3)保證數據的可靠性。即便某個數據節點出現故障失效,也不會形成數據丟失。

  數據存取策略

  數據的存取策略包括數據存放、數據讀取和數據複製等方面,它在很大程度上會影響整個分佈式文件系統的讀寫性能,是分佈式文件系統的核心內容。

  1.數據存放

  爲了提升數據的可靠性與系統的可用性,以及充分利用網絡帶寬,HDFS採用了以機架(Rack)爲基礎的數據存取策略。一個HDFS集羣一般包含多個機架,不一樣機架之間的數據通訊須要通過交換機或者路由器,同一個機架中不一樣機器之間的通訊則不須要通過交換機和路由器,這意味着同一個機架中不一樣機器之間的通訊要比不一樣機架之間的通訊帶寬大。

  HDFS默認每一個數據節點都是在不一樣的機架上,這種方法會存在一個缺點,那就是寫入數據的時候不能很充分利用同一機架內部機器之間的帶寬。可是,與這點缺點相比,這種方法也帶來了更多顯著的優勢:首先,能夠得到很高的數據可靠性,即便一個機架發生故障,位於其餘機架上的數據副本仍然是可用的;其次,在讀取數據的時候,能夠在多個機架上並行讀取數據,大大提升了數據讀取速度;最後,能夠更容易地實現系統內部負載均衡和錯誤處理。

  HDFS默認的冗餘因子是3,每個文件塊都會被同時保存到3個地方,其中,有兩份副本放在同一個機架的不一樣機器上,第三個副本放在不一樣的機架上,這樣既能夠保證機架發生異常時的數據恢復,也能夠提升數據讀寫性能。通常而言,HDFS副本的放置策略以下:

  (1)若是是在集羣內部發起寫操做請求,則把第一副本放置在發起寫操做請求的數據節點上,實現就近寫入數據。若是是來自集羣外部的寫操做,則從集羣內部挑選一臺磁盤不太滿、CPU不太忙的數據節點,做爲第一副本的存放地。

  (2)第二副本會被放置在與第一副本不一樣的機架的數據節點上。

  (3)第三副本會被放置在與第一副本相同的機架的其餘節點上。

  (4)若是還有更多的副本,則繼續從集羣中隨機選擇數據節點進行存放。

  2.數據讀取

  HDFS提供了一個API能夠肯定一個數據節點所屬的機架ID,客戶端也能夠調用API來獲取本身所屬的機架ID。當客戶端讀取數據時,從名稱節點得到數據塊不一樣副本的存放位置列表,列表中包含了副本所在的數據節點,能夠調用API來肯定客戶端和這些數據節點所屬的機架ID。當發現某個數據塊副本對應的機架ID和客戶端對應的機架ID相同時,就優先選擇該副本讀取數據,若是沒有發現,就隨機選擇一個副本讀取數據。

  3.數據複製

  HDFS的數據複製採用了流水線複製的策略,大大提升了數據複製過程的效率。當客戶端要往HDFS中寫入一個文件時,這個文件會首先被寫入本地,並被切分紅若干塊,每一個塊的大小是由HDFS的設定值來決定的。每一個塊都向HDFS集羣中的名稱節點發起寫請求,名稱節點會根據系統中各個數據節點的使用狀況,選擇一個數據節點列表返回給客戶端,而後客戶端就把數據首先寫入列表中的第一個數據節點,同時把列表傳給第一個數據節點,當第一個數據節點接收到4KB數據的時候,寫入本地,而且向列表中的第二個數據節點發起鏈接請求,把本身已經收到的4KB數據和列表傳給第二個數據節點,當第二個數據節點接收到4KB數據的時候,寫入本地,而且向列表中的第三個數據節點發起鏈接請求,依次類推,列表中的多個數據節點行成一條數據複製的流水線。最後,當文件寫完的時候,數據複製也同時完成。

  數據錯誤與恢復

  HDFS具備較高的容錯性,能夠兼容廉價的硬件,它把硬件出錯當作一種常態,而不是異常,並設計了相應的機制檢測數據錯誤和進行自動恢復,主要包括如下3種情形。

  1.名稱節點出錯

  名稱節點保存了全部的元數據信息,其中最核心的兩大數據結構是FsImage和EditLog,若是這兩個文件發生損壞,那麼整個HDFS實例將失效。Hadoop採用兩種機制來確保名稱節點的安全:第一,把名稱節點上的元數據信息同步存儲到其餘文件系統中(好比遠程掛載的網絡文件系統NFS)中;第二,運行一個第二名稱節點,當名稱節點宕機之後,能夠把第二名稱節點做爲一種彌補措施,利用第二名稱節點中的元數據信息進行系統恢復,可是從前面對第二名稱節點的介紹中能夠看出,這樣作仍然會丟失部分數據。所以,通常會把上述兩種方式結合使用,當名稱節點發生宕機時,首先到遠程掛載的網絡文件系統中獲取備份的元數據信息,放到第二名稱節點上進行恢復,並把第二名稱節點做爲名稱節點來使用。

  2.數據節點出錯

  每一個數據節點都會按期向名稱節點發送「心跳」信息,向名稱節點報告本身的狀態。當數據節點發生故障,或者網絡發生斷網時,名稱節點就沒法收到來自一些數據節點的「心跳」信息,這時這些數據節點就會被標記爲「宕機」,節點上面的全部數據都會被標記爲「不可讀」,名稱節點不會再給它們發送任何I/O請求。這時,有可能會出現一種情形,即因爲一些數據節點的不可用會致使一些數據塊的副本數量小於冗餘因子。名稱節點會按期檢查這種狀況,一旦發現某個數據塊的副本數量小於冗餘因子,就會啓動數據冗餘複製,爲它生成新的副本。HDFS與其餘分佈式文件系統的最大區別就是能夠調整冗餘數據的位置。

  3.數據出錯

  網絡傳輸和磁盤錯誤等因素都會形成數據錯誤。客戶端在讀取到數據後,會採用md5和sha1對數據塊進行校驗,以肯定讀取到正確的數據。在文件被建立時,客戶端就會對每個文件塊進行信息摘錄,並把這些信息寫入到同一個路徑的隱藏文件裏面。當客戶端讀取文件的時候,會先讀取該信息文件,而後利用該信息文件對每一個讀取的文件塊進行校驗。若是校驗出錯,客戶端就會請求到另一個數據節點讀取該文件塊,而且向名稱節點報告這個文件塊有錯誤,名稱節點會按期檢查而且從新複製這個塊。


 HDFS的數據讀寫過程

  在介紹HDFS的數據讀寫以前,須要簡單介紹一下相關的類。FileSystem是一個通用文件系統的抽象基類,能夠被分佈式文件系統繼承,全部可能使用Hadoop文件系統的代碼都要使用這個類。Hadoop爲FileSystem這個抽象類提供了多種具體的實現,DistributedFileSystem就是FileSystem在HDFS文件系統中的實現。FileSystem的open()方法返回的是一個輸入流FSDataInputStream對象,在HDFS文件系統中具體的輸入流就是DFSInputStream;FileSystem中的create()方法返回的是一個輸出流FSDataOutputStream對象,在HDFS文件系統中具體的輸出流就是DFSOutputStream。

  讀數據的過程

  客戶端連續調用oepn()、read()、close()讀取數據時,HDFS內部的執行過程以下:

  (1)客戶端經過FileSystem.open()打開文件,相應地,在HDFS文件系統中DistributedFileSystem具體實現了FileSystem。所以,調用open()方法後,DistributeFileSystem會建立輸入流FSDataFileSystem,對於HDFS而言,具體的輸入流就是DFSInputStream。

  (2)在DFSInputStream的構造函數中,輸入流經過ClientProtocal.getBlockLocations()遠程調用名稱節點,得到文件開始部分數據塊的保存位置,同時根據距離客戶端的遠近對數據節點進行排序;而後,DistributedFileSystem會利用DFSInputStream來實例化FSDataInputStream,返回給客戶端,同時返回了數據塊的數據節點地址。

  (3)得到輸入流FSDataInputStream後,客戶端調用read()函數開始讀取數據。輸入流根據前面的排序結果,選擇距離客戶端最近的數據節點創建鏈接並讀取數據。

  (4)數據從該數據節點讀到客戶端;當該數據塊讀取完畢時,FSDataInputStream關閉和該數據節點的鏈接。

  (5)輸入流經過getBlockLocations()方法查找下一個數據塊(若是客戶端緩存中已經包含了該數據塊的位置信息,就不須要調用該方法)。

  (6)找到該數據塊的最佳數據節點,讀取數據。

  (7)當客戶端讀取完畢數據的時候,調用FSDataInputStream的close()函數,關閉輸入流。

  須要注意的是,在讀取數據的過程當中,若是客戶端與數據節點通訊時出現錯誤,就會嘗試鏈接包含此數據塊的下一個數據節點。

  寫數據的過程

  客戶端向HDFS寫數據是一個複雜的過程,這裏介紹一下在不發生異常的狀況下,客戶端連續調用create()、write()、close()時,HDFS內部的執行過程。

  (1)客戶端經過FileSystem.create()建立文件,相應地,在HDFS文件系統中DistributedFileSystem具體實現了FileSystem。所以,在調用create()方法後,DistributeFileSystem會建立輸出流FSDataOutputStream,對於HDFS而言,具體的輸出流就是DFSOutputStream。

  (2)而後,DistributedFileSystem經過RPC遠程調用名稱節點,在文件系統的命名空間中建立一個新的文件。名稱節點會執行一些檢查,好比文件是否已經存在、客戶端是否有權限建立文件等。檢查經過以後,名稱節點會構造一個新文件,並添加文件信息。遠程方法調用結束後,DistributedFileSystem會利用DFSOutputStream來實例化FSDataOutputStream,返回給客戶端,客戶端使用這個輸出流寫入數據。

  (3)得到輸出流FSDataOutputStream之後,客戶端調用輸出流的write()方法向HDFS中對應的文件寫數據。

  (4)客戶端向輸出流FSDataOutputStream中寫入的數據會首先被分紅一個個的分包,這些分包被放入DFSOutputStream對象的內部隊列。輸出流FSDataOutputStream會向名稱節點申請保存文件和副本數據塊的若干個數據節點,這些數據節點造成一個數據流管道。隊列中的分包最後被打包成數據包,發往數據流管道中的第一個數據節點,第一個數據節點將數據包發送給第二個數據節點,第二個數據節點將數據包發送給第三個數據節點,這樣,數據包就會流經管道上的各個數據節點(流水線複製策略)。

  (5)由於各個數據節點位於不一樣的機器上,數據須要經過網絡發送,所以,爲了保證數據節點的數據都是準確的,接收到數據的數據節點要向發送者發送「確認包」。確認包沿着數據流管道逆流而上,從數據管道依次通過各個數據節點並最終發往客戶端,當客戶端收到應答時,它將對應的包從內部隊列中移除。不斷執行(3)~(5)步,直到數據所有寫完。

  (6)客戶端調用close()方法關閉數據流,此時開始,客戶端不會再向輸出流中寫入數據,因此,當DFSOutputStream對象內部隊列中的包都收到應答之後,就可使用ClientProtocol.complete()方法通知名稱節點關閉文件,完成一次正常的寫文件過程。

相關文章
相關標籤/搜索