引言node
Hadoop分佈式文件系統(HDFS)被設計成適合運行在通用硬件(commodity hardware)上的分佈式文件系統。它和現有的分佈式文件系統有不少共同點。但同時,它和其餘的分佈式文件系統的區別也是很明顯的。HDFS是一個高 度容錯性的系統,適合部署在廉價的機器上。HDFS能提供高吞吐量的數據訪問,很是適合大規模數據集上的應用。HDFS放寬了一部分POSIX約束,來實 現流式讀取文件系統數據的目的。HDFS在最開始是做爲Apache Nutch搜索引擎項目的基礎架構而開發的。HDFS是Apache Hadoop Core項目的一部分。這個項目的地址是http://hadoop.apache.org/core/。shell
前提和設計目標apache
硬件錯誤 瀏覽器
硬件錯誤是常態而不是異常。HDFS可能由成百上千的服務器所構成,每一個服務器上存儲着文件系統的部分數據。咱們面對的現實是構成系統的組件數 目是巨大的,並且任一組件都有可能失效,這意味着老是有一部分HDFS的組件是不工做的。所以錯誤檢測和快速、自動的恢復是HDFS最核心的架構目標。緩存
流式數據訪問 安全
運行在HDFS上的應用和普通的應用不一樣,須要流式訪問它們的數據集。HDFS的設計中更多的考慮到了數據批處理,而不是用戶交互處理。比之數 據訪問的低延遲問題,更關鍵的在於數據訪問的高吞吐量。POSIX標準設置的不少硬性約束對HDFS應用系統不是必需的。爲了提升數據的吞吐量,在一些關 鍵方面對POSIX的語義作了一些修改。bash
大規模數據集 服務器
運行在HDFS上的應用具備很大的數據集。HDFS上的一個典型文件大小通常都在G字節至T字節。所以,HDFS被調節以支持大文件存儲。它應該能提供總體上高的數據傳輸帶寬,能在一個集羣裏擴展到數百個節點。一個單一的HDFS實例應該能支撐數以千萬計的文件。網絡
簡單的一致性模型 數據結構
HDFS應用須要一個「一次寫入屢次讀取」的文件訪問模型。一個文件通過建立、寫入和關閉以後就不須要改變。這一假設簡化了數據一致性問題,並 且使高吞吐量的數據訪問成爲可能。Map/Reduce應用或者網絡爬蟲應用都很是適合這個模型。目前還有計劃在未來擴充這個模型,使之支持文件的附加寫 操做。
「移動計算比移動數據更划算」
一個應用請求的計算,離它操做的數據越近就越高效,在數據達到海量級別的時候更是如此。由於這樣就能下降網絡阻塞的影響,提升系統數據的吞吐量。將計算移動到數據附近,比之將數據移動到應用所在顯然更好。HDFS爲應用提供了將它們本身移動到數據附近的接口。
異構軟硬件平臺間的可移植性
HDFS在設計的時候就考慮到平臺的可移植性。這種特性方便了HDFS做爲大規模數據應用平臺的推廣。
Namenode 和 Datanode
HDFS採用master/slave架構。一個HDFS集羣是由一個Namenode和必定數目的Datanodes組成。Namenode 是一箇中心服務器,負責管理文件系統的名字空間(namespace)以及客戶端對文件的訪問。集羣中的Datanode通常是一個節點一個,負責管理它 所在節點上的存儲。HDFS暴露了文件系統的名字空間,用戶可以以文件的形式在上面存儲數據。從內部看,一個文件其實被分紅一個或多個數據塊,這些塊存儲 在一組Datanode上。Namenode執行文件系統的名字空間操做,好比打開、關閉、重命名文件或目錄。它也負責肯定數據塊到具體Datanode 節點的映射。Datanode負責處理文件系統客戶端的讀寫請求。在Namenode的統一調度下進行數據塊的建立、刪除和複製。
Namenode和Datanode被設計成能夠在普通的商用機器上運行。這些機器通常運行着GNU/Linux操做系統(OS)。HDFS採 用Java語言開發,所以任何支持Java的機器均可以部署Namenode或Datanode。因爲採用了可移植性極強的Java語言,使得HDFS可 以部署到多種類型的機器上。一個典型的部署場景是一臺機器上只運行一個Namenode實例,而集羣中的其它機器分別運行一個Datanode實例。這種 架構並不排斥在一臺機器上運行多個Datanode,只不過這樣的狀況比較少見。
集羣中單一Namenode的結構大大簡化了系統的架構。Namenode是全部HDFS元數據的仲裁者和管理者,這樣,用戶數據永遠不會流過Namenode。
文件系統的名字空間 (namespace)
HDFS支持傳統的層次型文件組織結構。用戶或者應用程序能夠建立目錄,而後將文件保存在這些目錄裏。文件系統名字空間的層次結構和大多數現有 的文件系統相似:用戶能夠建立、刪除、移動或重命名文件。當前,HDFS不支持用戶磁盤配額和訪問權限控制,也不支持硬連接和軟連接。可是HDFS架構並 不妨礙實現這些特性。
Namenode負責維護文件系統的名字空間,任何對文件系統名字空間或屬性的修改都將被Namenode記錄下來。應用程序能夠設置HDFS保存的文件的副本數目。文件副本的數目稱爲文件的副本系數,這個信息也是由Namenode保存的。
數據複製
HDFS被設計成可以在一個大集羣中跨機器可靠地存儲超大文件。它將每一個文件存儲成一系列的數據塊,除了最後一個,全部的數據塊都是一樣大小 的。爲了容錯,文件的全部數據塊都會有副本。每一個文件的數據塊大小和副本系數都是可配置的。應用程序能夠指定某個文件的副本數目。副本系數能夠在文件建立 的時候指定,也能夠在以後改變。HDFS中的文件都是一次性寫入的,而且嚴格要求在任什麼時候候只能有一個寫入者。
Namenode全權管理數據塊的複製,它週期性地從集羣中的每一個Datanode接收心跳信號和塊狀態報告(Blockreport)。接收到心跳信號意味着該Datanode節點工做正常。塊狀態報告包含了一個該Datanode上全部數據塊的列表。
副本存放: 最最開始的一步
副本的存放是HDFS可靠性和性能的關鍵。優化的副本存放策略是HDFS區分於其餘大部分分佈式文件系統的重要特性。這種特性須要作大量的調 優,並須要經驗的積累。HDFS採用一種稱爲機架感知(rack-aware)的策略來改進數據的可靠性、可用性和網絡帶寬的利用率。目前實現的副本存放 策略只是在這個方向上的第一步。實現這個策略的短時間目標是驗證它在生產環境下的有效性,觀察它的行爲,爲實現更先進的策略打下測試和研究的基礎。
大型HDFS實例通常運行在跨越多個機架的計算機組成的集羣上,不一樣機架上的兩臺機器之間的通信須要通過交換機。在大多數狀況下,同一個機架內的兩臺機器間的帶寬會比不一樣機架的兩臺機器間的帶寬大。
經過一個機架感知的過程,Namenode能夠肯定每一個Datanode所屬的機架id。一個簡單但沒有優化的策略就是將副本存放在不一樣的機架 上。這樣能夠有效防止當整個機架失效時數據的丟失,而且容許讀數據的時候充分利用多個機架的帶寬。這種策略設置能夠將副本均勻分佈在集羣中,有利於當組件 失效狀況下的負載均衡。可是,由於這種策略的一個寫操做須要傳輸數據塊到多個機架,這增長了寫的代價。
在大多數狀況下,副本系數是3,HDFS的存放策略是將一個副本存放在本地機架的節點上,一個副本放在同一機架的另外一個節點上,最後一個副本放 在不一樣機架的節點上。這種策略減小了機架間的數據傳輸,這就提升了寫操做的效率。機架的錯誤遠遠比節點的錯誤少,因此這個策略不會影響到數據的可靠性和可 用性。於此同時,由於數據塊只放在兩個(不是三個)不一樣的機架上,因此此策略減小了讀取數據時須要的網絡傳輸總帶寬。在這種策略下,副本並非均勻分佈在 不一樣的機架上。三分之一的副本在一個節點上,三分之二的副本在一個機架上,其餘副本均勻分佈在剩下的機架中,這一策略在不損害數據可靠性和讀取性能的狀況 下改進了寫的性能。
當前,這裏介紹的默認副本存放策略正在開發的過程當中。
副本選擇
爲了下降總體的帶寬消耗和讀取延時,HDFS會盡可能讓讀取程序讀取離它最近的副本。若是在讀取程序的同一個機架上有一個副本,那麼就讀取該副本。若是一個HDFS集羣跨越多個數據中心,那麼客戶端也將首先讀本地數據中心的副本。
安全模式
Namenode啓動後會進入一個稱爲安全模式的特殊狀態。處於安全模式的Namenode是不會進行數據塊的複製的。Namenode從全部 的 Datanode接收心跳信號和塊狀態報告。塊狀態報告包括了某個Datanode全部的數據塊列表。每一個數據塊都有一個指定的最小副本數。當 Namenode檢測確認某個數據塊的副本數目達到這個最小值,那麼該數據塊就會被認爲是副本安全(safely replicated)的;在必定百分比(這個參數可配置)的數據塊被Namenode檢測確認是安全以後(加上一個額外的30秒等待時 間),Namenode將退出安全模式狀態。接下來它會肯定還有哪些數據塊的副本沒有達到指定數目,並將這些數據塊複製到其餘Datanode上。
文件系統元數據的持久化
Namenode上保存着HDFS的名字空間。對於任何對文件系統元數據產生修改的操做,Namenode都會使用一種稱爲EditLog的事 務日誌記錄下來。例如,在HDFS中建立一個文件,Namenode就會在Editlog中插入一條記錄來表示;一樣地,修改文件的副本系數也將往 Editlog插入一條記錄。Namenode在本地操做系統的文件系統中存儲這個Editlog。整個文件系統的名字空間,包括數據塊到文件的映射、文 件的屬性等,都存儲在一個稱爲FsImage的文件中,這個文件也是放在Namenode所在的本地文件系統上。
Namenode在內存中保存着整個文件系統的名字空間和文件數據塊映射(Blockmap)的映像。這個關鍵的元數據結構設計得很緊湊,於是 一個有4G內存的Namenode足夠支撐大量的文件和目錄。當Namenode啓動時,它從硬盤中讀取Editlog和FsImage,將全部 Editlog中的事務做用在內存中的FsImage上,並將這個新版本的FsImage從內存中保存到本地磁盤上,而後刪除舊的Editlog,由於這 箇舊的Editlog的事務都已經做用在FsImage上了。這個過程稱爲一個檢查點(checkpoint)。在當前實現中,檢查點只發生在 Namenode啓動時,在不久的未來將實現支持週期性的檢查點。
Datanode將HDFS數據以文件的形式存儲在本地的文件系統中,它並不知道有關HDFS文件的信息。它把每一個HDFS數據塊存儲在本地文 件系統的一個單獨的文件中。Datanode並不在同一個目錄建立全部的文件,實際上,它用試探的方法來肯定每一個目錄的最佳文件數目,而且在適當的時候創 建子目錄。在同一個目錄中建立全部的本地文件並非最優的選擇,這是由於本地文件系統可能沒法高效地在單個目錄中支持大量的文件。當一個Datanode 啓動時,它會掃描本地文件系統,產生一個這些本地文件對應的全部HDFS數據塊的列表,而後做爲報告發送到Namenode,這個報告就是塊狀態報告。
通信協議
全部的HDFS通信協議都是創建在TCP/IP協議之上。客戶端經過一個可配置的TCP端口鏈接到Namenode,經過 ClientProtocol協議與Namenode交互。而Datanode使用DatanodeProtocol協議與Namenode交互。一個遠 程過程調用(RPC)模型被抽象出來封裝ClientProtocol和Datanodeprotocol協議。在設計上,Namenode不會主動發起 RPC,而是響應來自客戶端或 Datanode 的RPC請求。
健壯性
HDFS的主要目標就是即便在出錯的狀況下也要保證數據存儲的可靠性。常見的三種出錯狀況是:Namenode出錯, Datanode出錯和網絡割裂(network partitions)。
磁盤數據錯誤,心跳檢測和從新複製
每一個Datanode節點週期性地向Namenode發送心跳信號。網絡割裂可能致使一部分Datanode跟Namenode失去聯繫。 Namenode經過心跳信號的缺失來檢測這一狀況,並將這些近期再也不發送心跳信號Datanode標記爲宕機,不會再將新的IO請求發給它們。任何存儲 在宕機Datanode上的數據將再也不有效。Datanode的宕機可能會引發一些數據塊的副本系數低於指定值,Namenode不斷地檢測這些須要複製 的數據塊,一旦發現就啓動複製操做。在下列狀況下,可能須要從新複製:某個Datanode節點失效,某個副本遭到損壞,Datanode上的硬盤錯誤, 或者文件的副本系數增大。
集羣均衡
DFS的架構支持數據均衡策略。若是某個Datanode節點上的空閒空間低於特定的臨界點,按照均衡策略系統就會自動地將數據從這個 Datanode移動到其餘空閒的Datanode。當對某個文件的請求忽然增長,那麼也可能啓動一個計劃建立該文件新的副本,而且同時從新平衡集羣中的 其餘數據。這些均衡策略目前尚未實現。
數據完整性
從某個Datanode獲取的數據塊有多是損壞的,損壞多是由Datanode的存儲設備錯誤、網絡錯誤或者軟件bug形成的。HDFS客 戶端軟件實現了對HDFS文件內容的校驗和(checksum)檢查。當客戶端建立一個新的HDFS文件,會計算這個文件每一個數據塊的校驗和,並將校驗和 做爲一個單獨的隱藏文件保存在同一個HDFS名字空間下。當客戶端獲取文件內容後,它會檢驗從Datanode獲取的數據跟相應的校驗和文件中的校驗和是 否匹配,若是不匹配,客戶端能夠選擇從其餘Datanode獲取該數據塊的副本。
元數據磁盤錯誤
FsImage和Editlog是HDFS的核心數據結構。若是這些文件損壞了,整個HDFS實例都將失效。於是,Namenode能夠配置成 支持維護多個FsImage和Editlog的副本。任何對FsImage或者Editlog的修改,都將同步到它們的副本上。這種多副本的同步操做可能 會下降Namenode每秒處理的名字空間事務數量。然而這個代價是能夠接受的,由於即便HDFS的應用是數據密集的,它們也非元數據密集的。當 Namenode重啓的時候,它會選取最近的完整的FsImage和Editlog來使用。
Namenode是HDFS集羣中的單點故障(single point of failure)所在。若是Namenode機器故障,是須要手工干預的。目前,自動重啓或在另外一臺機器上作Namenode故障轉移的功能還沒實現。
快照
快照支持某一特定時刻的數據的複製備份。利用快照,可讓HDFS在數據損壞時恢復到過去一個已知正確的時間點。HDFS目前還不支持快照功能,但計劃在未來的版本進行支持。
數據組織
數據塊
HDFS被設計成支持大文件,適用HDFS的是那些須要處理大規模的數據集的應用。這些應用都是隻寫入數據一次,但卻讀取一次或屢次,而且讀取 速度應能知足流式讀取的須要。HDFS支持文件的「一次寫入屢次讀取」語義。一個典型的數據塊大小是64MB。於是,HDFS中的文件老是按照64M被切 分紅不一樣的塊,每一個塊儘量地存儲於不一樣的Datanode中。
Staging
客戶端建立文件的請求其實並無當即發送給Namenode,事實上,在剛開始階段HDFS客戶端會先將文件數據緩存到本地的一個臨時文件。應 用程序的寫操做被透明地重定向到這個臨時文件。當這個臨時文件累積的數據量超過一個數據塊的大小,客戶端纔會聯繫Namenode。Namenode將文 件名插入文件系統的層次結構中,而且分配一個數據塊給它。而後返回Datanode的標識符和目標數據塊給客戶端。接着客戶端將這塊數據從本地臨時文件上 傳到指定的Datanode上。當文件關閉時,在臨時文件中剩餘的沒有上傳的數據也會傳輸到指定的Datanode上。而後客戶端告訴Namenode文 件已經關閉。此時Namenode纔將文件建立操做提交到日誌裏進行存儲。若是Namenode在文件關閉前宕機了,則該文件將丟失。
上述方法是對在HDFS上運行的目標應用進行認真考慮後獲得的結果。這些應用須要進行文件的流式寫入。若是不採用客戶端緩存,因爲網絡速度和網 絡堵塞會對吞估量形成比較大的影響。這種方法並非沒有先例的,早期的文件系統,好比AFS,就用客戶端緩存來提升性能。爲了達到更高的數據上傳效率,已 經放鬆了POSIX標準的要求。
流水線複製
當客戶端向HDFS文件寫入數據的時候,一開始是寫到本地臨時文件中。假設該文件的副本系數設置爲3,當本地臨時文件累積到一個數據塊的大小 時,客戶端會從Namenode獲取一個Datanode列表用於存放副本。而後客戶端開始向第一個Datanode傳輸數據,第一個Datanode一 小部分一小部分(4 KB)地接收數據,將每一部分寫入本地倉庫,並同時傳輸該部分到列表中第二個Datanode節點。第二個Datanode也是這樣,一小部分一小部分地 接收數據,寫入本地倉庫,並同時傳給第三個Datanode。最後,第三個Datanode接收數據並存儲在本地。所以,Datanode能流水線式地從 前一個節點接收數據,並在同時轉發給下一個節點,數據以流水線的方式從前一個Datanode複製到下一個。
可訪問性
HDFS給應用提供了多種訪問方式。用戶能夠經過Java API接口訪問,也能夠經過C語言的封裝API訪問,還能夠經過瀏覽器的方式訪問HDFS中的文件。經過WebDAV協議訪問的方式正在開發中。
DFSShell
HDFS以文件和目錄的形式組織用戶數據。它提供了一個命令行的接口(DFSShell)讓用戶與HDFS中的數據進行交互。命令的語法和用戶熟悉的其餘shell(例如 bash, csh)工具相似。下面是一些動做/命令的示例:
DFSShell 能夠用在那些經過腳本語言和文件系統進行交互的應用程序上。
DFSAdmin
DFSAdmin 命令用來管理HDFS集羣。這些命令只有HDSF的管理員才能使用。下面是一些動做/命令的示例:
瀏覽器接口
一個典型的HDFS安裝會在一個可配置的TCP端口開啓一個Web服務器用於暴露HDFS的名字空間。用戶能夠用瀏覽器來瀏覽HDFS的名字空間和查看文件的內容。
存儲空間回收
文件的刪除和恢復
當用戶或應用程序刪除某個文件時,這個文件並無馬上從HDFS中刪除。實際上,HDFS會將這個文件重命名轉移到/trash目錄。只要文件 還在/trash目錄中,該文件就能夠被迅速地恢復。文件在/trash中保存的時間是可配置的,當超過這個時間時,Namenode就會將該文件從名字 空間中刪除。刪除文件會使得該文件相關的數據塊被釋放。注意,從用戶刪除文件到HDFS空閒空間的增長之間會有必定時間的延遲。
只要被刪除的文件還在/trash目錄中,用戶就能夠恢復這個文件。若是用戶想恢復被刪除的文件,他/她能夠瀏覽/trash目錄找回該文件。 /trash目錄僅僅保存被刪除文件的最後副本。/trash目錄與其餘的目錄沒有什麼區別,除了一點:在該目錄上HDFS會應用一個特殊策略來自動刪除 文件。目前的默認策略是刪除/trash中保留時間超過6小時的文件。未來,這個策略能夠經過一個被良好定義的接口配置。
減小副本系數
當一個文件的副本系數被減少後,Namenode會選擇過剩的副本刪除。下次心跳檢測時會將該信息傳遞給Datanode。Datanode遂 即移除相應的數據塊,集羣中的空閒空間加大。一樣,在調用setReplication API結束和集羣中空閒空間增長間會有必定的延遲。