從一般分布式設計看HDFS設計思想與架構


    要想深入學習HDFS就要先了解其設計思想和架構,這樣才能繼續深入使用HDFS或者深入研究源代碼。懂得了“所以然”才能在實際使用中靈活運用、快速解決遇到的問題。下面這篇博文我們就先從一般的分布式談起,在宏觀上逐步去探究HDFS的設計思想和架構實現。

一.先談分布式

  分布式是近幾年非常火的技術概念,無論是雲計算、大數據還是高並發的互聯網架構話題都會頻頻出現這個詞語,特別是這個大談“大規模”的時代,分布式貌似成了高大上技術的代名詞。引的許多剛入行的技術人員趨之若鶩,其實世界上不會有憑空出現的事物,都是慢慢演化的,新事物一定可以找到舊事物的影子。只要打好基礎,抓住技術演進的主線,結合實踐慢慢積累就可以了。但是話又說回來,分布式系統確實在實現上難度上確實要高於一般的業務系統,門檻也要高一些。

  那么我們就先看看“一般的”分布式系統需要解決那些問題、這些問題的通用解決方案和特性。限於篇幅,如要深入了解某個協議和算法請參考相關文獻。

  1.定義

  分布式系統會划分成多個子系統或模塊,各自運行在不同的機器上,子系統或模塊之間通過網絡通信進行協作,實現最終的整體功能。比如分布式操作系統、分布式程序設計語言及其編譯(解釋)系統、分布式文件系統和分布式數據庫系統等。利用多個節點共同協作完成一項或多項具體業務功能的系統就是分布式系統。

  舉例:SolrCloud

   A. 一個solrcloud集群通常有多台solr服務器

          B.  每一個solr服務器節點負責存儲整個索引庫的若干個shard(數據分片)

          C.  每一個shard又有多台服務器存放若干個副本互為主備用

          D.  索引的建立和查詢會在整個集群的各個節點上並發執行

          E.  SolrCloud集群作為整體對外服務,而其內部細節可對客戶端透明

  2.問題及方案

  1)CAP的權衡

  分布式領域有一個非常著名的CAP理論,是由 Eric Brewer 提出的分布式系統中最為重要的理論之一。其定義很好理解,CAP 三個字母分別代表了分布式系統中三個相互矛盾的屬性。CAP分別代表Consistency、Availiablity、Tolerance to the partition of network即一致性、可用性、網絡分區容忍性。

  一致性(Consistency):在CAP理論中的一致性是強一致性,即每個節點上的數據時刻保持一致。

  可用性(Availiablity):是指分布式系統在出現異常情況的時候的可用度。

  分區容忍性(Tolerance...):是指分布式系統對網絡分區的容錯度。

  CAP 理論指出:無法設計一種分布式協議,使得同時完全具備 CAP 三個屬性,即該種協議下的副本始終是強一致性&服務始終是可用的&協議可以容忍任何網絡分區異常;分布式系統協議只能在 CAP 這三者間所有折中。

    CAP折中的實現可以體現在分布式協議中:

  a. Lease 機制犧牲了部分異常情況下的 A,從而獲得了完全的 C 與很好的 P。

  b. Quorum 機制,即總共有 N 個副本,成功更新 W 個副本則算成功提交,讀取時讀 R 個副本。這種一般的 Quorum 機制,在 CAP 三大因素中都各做了折中,有一定的 C,有較好的 A,也有較好的 P,是一種較為平衡的分布式協議。

  c. 兩階段提交系統具有完全的 C,很不好 A,很不好 P。

  d. Paxos 協議具有完全的 C,較好的 A,較好的 P

  2)負載均衡

  在某些有多個節點的分布式系統中需要對服務請求進行負載均衡,根據業務需求的不同也可以使用不同的負載均衡算法,例如一致性Hash。

  3)高並發

  有些分布式系統對並發性有很高的要求,通常是使用MVCC:Multiversion concurrency control,多版本並發控制技術。本質是使用COW+Version+CAS這個技術組合來提升系統並發性。

二.HDFS的架構與設計

  分布式服務主要有分布式存儲、計算、協調服務,HDFS是作為最底層的分布式存儲服務而存在的,是Hadoop的分布式文件系統組件,它與現有的分布式文件系統有很多相似之處。然而與其他的分布式文件系統的差異也是顯着的。HDFS是高容錯的,被設計成在低成本硬件上部署。HDFS為應用數據提供高吞吐量的訪問,適用於具有大規模數據集的應用程序。HDFS放松了一些POSIX的要求,以便提供流式方式來訪問文件系統數據。HDFS的最初是作為Apache Nutch網絡搜索引擎項目的基礎。目前HDFS是一個Apache Hadoop的子項目。

  1.HDFS設計目標

  1)硬件錯誤是常態,而非異常情況,HDFS可能是有成百上千的server組成,任何一個組件都有可能一直失效,因此錯誤檢測和快速、自動的恢復是HDFS的核心架構目標。
       2)跑在HDFS上的應用與一般的應用不同,它們主要是以流式讀為主,做批量處理;比之關注數據訪問的低延遲問題,更關鍵的在於數據訪問的高吞吐量。
       3)HDFS以支持大數據集合為目標,一個存儲在上面的典型文件大小一般都在千兆至T字節,一個單一HDFS實例應該能支撐數以千萬計的文件。
       4)HDFS應用對文件要求的是write-one-read-many訪問模型。一個文件經過創建、寫,關閉之后就不需要改變。這一假設簡化了數據一致性問 題,使高吞吐量的數據訪問成為可能。典型的如MapReduce框架,或者一個web crawler應用都很適合這個模型。
       5)移動計算的代價比之移動數據的代價低。一個應用請求的計算,離它操作的數據越近就越高效,這在數據達到海量級別的時候更是如此。將計算移動到數據附近,比之將數據移動到應用所在顯然更好,HDFS提供給應用這樣的接口。
       6)在異構的硬件和軟件平台上的可移植性。

    2.HDFS核心組件-NameNode和DataNode

  HDFS采用master/slave架構。一個HDFS集群是有一個Namenode和一定數目的Datanode組成。Namenode是一個中心服務器,負責管理文件系統的namespace和客戶端對文件的訪問。Datanode在集群中一般是一個節點一個,負責管理節點上它們附帶的存儲。在內部,一個文件其實分成一個或多個block,這些block存儲在Datanode集合里。Namenode執行文件系統的namespace操作,例如打開、關閉、重命名文件和目錄,同時決定block到具體Datanode節點的映射。Datanode在Namenode的指揮下進行block的創建、刪除和復制。Namenode和Datanode都是設計成可以跑在普通的廉價的運行Linux的機器上。HDFS采用java語言開發,因此可以部署在很大范圍的機器上。一個典型的部署場景是一台機器跑一個單獨的Namenode節點,集群中的其他機器各跑一個Datanode實例。這個架構並不排除一台機器上跑多個Datanode,不過這比較少見。集群中單一Namenode的結構大大簡化了系統的架構。Namenode是所有HDFS元數據的仲裁者和管理者,這樣,用戶數據永遠不會流過Namenode。

   HDFS架構圖:

  

  3.名字空間(NameSpace)

   HDFS支持傳統的層次型文件組織結構。用戶或者應用程序可以創建目錄,然后將文件保存在這些目錄里。文件系統名字空間的層次結構和大多數現有的文件系統類似:用戶可以創建、刪除、移動或重命名文件。當前,HDFS不支持用戶磁盤配額和訪問權限控制,也不支持硬鏈接和軟鏈接。但是HDFS架構並不妨礙實現這些特性。Namenode負責維護文件系統的名字空間,任何對文件系統名字空間或屬性的修改都將被Namenode記錄下來。應用程序可以設置HDFS保存的文件的副本數目。文件副本的數目稱為文件的副本系數,這個信息也是由Namenode保存的。

  4.數據復制

  HDFS被設計成能夠在一個大集群中跨機器可靠地存儲超大文件。它將每個文件存儲成一系列的數據塊,除了最后一個,所有的數據塊都是同樣大小的。為了容錯,文件的所有數據塊都會有副本。每個文件的數據塊大小和副本系數都是可配置的。應用程序可以指定某個文件的副本數目。副本系數可以在文件創建的時候指定,也可以在之后改變。HDFS中的文件都是一次性寫入的,並且嚴格要求在任何時候只能有一個寫入者。Namenode全權管理數據塊的復制,它周期性地從集群中的每個Datanode接收心跳信號和塊狀態報告(Blockreport)。接收到心跳信號意味着該Datanode節點工作正常。塊狀態報告包含了一個該Datanode上所有數據塊的列表。

  5.副本存放

  副本存放是最開始的一步,是HDFS可靠性和性能的關鍵。優化的副本存放策略是HDFS區分於其他大部分分布式文件系統的重要特性。這種特性需要做大量的調優,並需要經驗的積累。HDFS采用一種稱為機架感知(rack-aware)的策略來改進數據的可靠性、可用性和網絡帶寬的利用率。大型HDFS實例一般運行在跨越多個機架的計算機組成的集群上,不同機架上的兩台機器之間的通訊需要經過交換機。在大多數情況下,同一個機架內的兩台機器間的帶寬會比不同機架的兩台機器間的帶寬大。通過一個機架感知的過程,Namenode可以確定每個Datanode所屬的機架id。一個簡單但沒有優化的策略就是將副本存放在不同的機架上。這樣可以有效防止當整個機架失效時數據的丟失,並且允許讀數據的時候充分利用多個機架的帶寬。這種策略設置可以將副本均勻分布在集群中,有利於當組件失效情況下的負載均衡。但是,因為這種策略的一個寫操作需要傳輸數據塊到多個機架,這增加了寫的代價。在大多數情況下,副本系數是3,HDFS的存放策略是將一個副本存放在本地機架的節點上,一個副本放在同一機架的另一個節點上,最后一個副本放在不同機架的節點上。這種策略減少了機架間的數據傳輸,這就提高了寫操作的效率。機架的錯誤遠遠比節點的錯誤少,所以這個策略不會影響到數據的可靠性和可用性。於此同時,因為數據塊只放在兩個(不是三個)不同的機架上,所以此策略減少了讀取數據時需要的網絡傳輸總帶寬。在這種策略下,副本並不是均勻分布在不同的機架上。三分之一的副本在一個節點上,三分之二的副本在一個機架上,其他副本均勻分布在剩下的機架中,這一策略在不損害數據可靠性和讀取性能的情況下改進了寫的性能。

  為了降低整體的帶寬消耗和讀取延時,HDFS會盡量讓讀取程序讀取離它最近的副本。如果在讀取程序的同一個機架上有一個副本,那么就讀取該副本。如果一個HDFS集群跨越多個數據中心,那么客戶端也將首先讀本地數據中心的副本。

  6.安全模式

  Namenode啟動后會進入一個稱為安全模式的特殊狀態。處於安全模式的Namenode是不會進行數據塊的復制的。Namenode從所有的 Datanode接收心跳信號和塊狀態報告。塊狀態報告包括了某個Datanode所有的數據塊列表。每個數據塊都有一個指定的最小副本數。當Namenode檢測確認某個數據塊的副本數目達到這個最小值,那么該數據塊就會被認為是副本安全(safely replicated)的;在一定百分比(這個參數可配置)的數據塊被Namenode檢測確認是安全之后(加上一個額外的30秒等待時間),Namenode將退出安全模式狀態。接下來它會確定還有哪些數據塊的副本沒有達到指定數目,並將這些數據塊復制到其他Datanode上。

  7.元數據的持久化和磁盤錯誤

  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)。Datanode將HDFS數據以文件的形式存儲在本地的文件系統中,它並不知道有關HDFS文件的信息。它把每個HDFS數據塊存儲在本地文件系統的一個單獨的文件中。Datanode並不在同一個目錄創建所有的文件,實際上,它用試探的方法來確定每個目錄的最佳文件數目,並且在適當的時候創建子目錄。在同一個目錄中創建所有的本地文件並不是最優的選擇,這是因為本地文件系統可能無法高效地在單個目錄中支持大量的文件。當一個Datanode啟動時,它會掃描本地文件系統,產生一個這些本地文件對應的所有HDFS數據塊的列表,然后作為報告發送到Namenode,這個報告就是塊狀態報告。

  FsImage和Editlog是HDFS的核心數據結構。如果這些文件損壞了,整個HDFS實例都將失效。因而,Namenode可以配置成支持維護多個FsImage和Editlog的副本。任何對FsImage或者Editlog的修改,都將同步到它們的副本上。這種多副本的同步操作可能會降低Namenode每秒處理的名字空間事務數量。然而這個代價是可以接受的,因為即使HDFS的應用是數據密集的,它們也非元數據密集的。當Namenode重啟的時候,它會選取最近的完整的FsImage和Editlog來使用。

  Namenode是HDFS集群中的單點故障(single point of failure)所在。如果Namenode機器故障,是需要手工干預的。目前,自動重啟或在另一台機器上做Namenode故障轉移的功能還沒實現。

  8.通信協議

  所有的HDFS通訊協議都是建立在TCP/IP協議之上。客戶端通過一個可配置的TCP端口連接到Namenode,通過ClientProtocol協議與Namenode交互。而Datanode使用DatanodeProtocol協議與Namenode交互。一個遠程過程調用(RPC)模型被抽象出來封裝ClientProtocol和Datanodeprotocol協議。在設計上,Namenode不會主動發起RPC,而是響應來自客戶端或 Datanode 的RPC請求。

  9.數據完整性和數據錯誤(心跳檢測和重新復制)

  每個Datanode節點周期性地向Namenode發送心跳信號。網絡分區可能導致一部分Datanode跟Namenode失去聯系。Namenode通過心跳信號的缺失來檢測這一情況,並將這些近期不再發送心跳信號Datanode標記為宕機,不會再將新的IO請求發給它們。任何存儲在宕機Datanode上的數據將不再有效。Datanode的宕機可能會引起一些數據塊的副本系數低於指定值,Namenode不斷地檢測這些需要復制的數據塊,一旦發現就啟動復制操作。在下列情況下,可能需要重新復制:某個Datanode節點失效,某個副本遭到損壞,Datanode上的硬盤錯誤,或者文件的副本系數增大。

  從某個Datanode獲取的數據塊有可能是損壞的,損壞可能是由Datanode的存儲設備錯誤、網絡錯誤或者軟件bug造成的。HDFS客戶端軟件實現了對HDFS文件內容的校驗和(checksum)檢查。當客戶端創建一個新的HDFS文件,會計算這個文件每個數據塊的校驗和,並將校驗和作為一個單獨的隱藏文件保存在同一個HDFS名字空間下。當客戶端獲取文件內容后,它會檢驗從Datanode獲取的數據跟相應的校驗和文件中的校驗和是否匹配,如果不匹配,客戶端可以選擇從其他Datanode獲取該數據塊的副本。

  10.數據塊&客戶端緩存&流水線復制

  HDFS被設計成支持大文件,適用HDFS的是那些需要處理大規模的數據集的應用。這些應用都是只寫入數據一次,但卻讀取一次或多次,並且讀取速度應能滿足流式讀取的需要。HDFS支持文件的“一次寫入多次讀取”語義。一個典型的數據塊大小是64MB。因而,HDFS中的文件總是按照64M被切分成不同的塊,每個塊盡可能地存儲於不同的Datanode中。

  客戶端創建文件的請求其實並沒有立即發送給Namenode,事實上,在剛開始階段HDFS客戶端會先將文件數據緩存到本地的一個臨時文件。應用程序的寫操作被透明地重定向到這個臨時文件。當這個臨時文件累積的數據量超過一個數據塊的大小,客戶端才會聯系Namenode。Namenode將文件名插入文件系統的層次結構中,並且分配一個數據塊給它。然后返回Datanode的標識符和目標數據塊給客戶端。接着客戶端將這塊數據從本地臨時文件上傳到指定的Datanode上。當文件關閉時,在臨時文件中剩余的沒有上傳的數據也會傳輸到指定的Datanode上。然后客戶端告訴Namenode文件已經關閉。此時Namenode才將文件創建操作提交到日志里進行存儲。如果Namenode在文件關閉前宕機了,則該文件將丟失。上述方法是對在HDFS上運行的目標應用進行認真考慮后得到的結果。這些應用需要進行文件的流式寫入。如果不采用客戶端緩存,由於網絡速度和網絡堵塞會對吞估量造成比較大的影響。

  當客戶端向HDFS文件寫入數據的時候,一開始是寫到本地臨時文件中。假設該文件的副本系數設置為3,當本地臨時文件累積到一個數據塊的大小時,客戶端會從Namenode獲取一個Datanode列表用於存放副本。然后客戶端開始向第一個Datanode傳輸數據,第一個Datanode一小部分一小部分(4 KB)地接收數據,將每一部分寫入本地倉庫,並同時傳輸該部分到列表中第二個Datanode節點。第二個Datanode也是這樣,一小部分一小部分地接收數據,寫入本地倉庫,並同時傳給第三個Datanode。最后,第三個Datanode接收數據並存儲在本地。因此,Datanode能流水線式地從前一個節點接收數據,並在同時轉發給下一個節點,數據以流水線的方式從前一個Datanode復制到下一個。

  11.文件的刪除和恢復

  當用戶或應用程序刪除某個文件時,這個文件並沒有立刻從HDFS中刪除。實際上,HDFS會將這個文件重命名轉移到/trash目錄。只要文件還在/trash目錄中,該文件就可以被迅速地恢復。文件在/trash中保存的時間是可配置的,當超過這個時間時,Namenode就會將該文件從名字空間中刪除。刪除文件會使得該文件相關的數據塊被釋放。注意,從用戶刪除文件到HDFS空閑空間的增加之間會有一定時間的延遲。只要被刪除的文件還在/trash目錄中,用戶就可以恢復這個文件。如果用戶想恢復被刪除的文件,他/她可以瀏覽/trash目錄找回該文件。/trash目錄僅僅保存被刪除文件的最后副本。/trash目錄與其他的目錄沒有什么區別,除了一點:在該目錄上HDFS會應用一個特殊策略來自動刪除文件。目前的默認策略是刪除/trash中保留時間超過6小時的文件。將來,這個策略可以通過一個被良好定義的接口配置。

  當一個文件的副本系數被減小后,Namenode會選擇過剩的副本刪除。下次心跳檢測時會將該信息傳遞給Datanode。Datanode遂即移除相應的數據塊,集群中的空閑空間加大。同樣,在調用setReplication API結束和集群中空閑空間增加間會有一定的延遲。

三.總結

   通過以上可以看出所有分布式系統都是有共性的,只是設計目標不同架構設計和具體實現方案也會有所差異,這也正是每個組件都有自己特定的應用場景的體現。HDFS作為大數據生態中最為底層和基礎的分布式存儲組件,其工作機制和架構策略是非常值得學習和參考的。結合實踐深入理解HDFS的原理和實現細節是很有必要的,有利於靈活運用和快速解決問題。

  進一步學習請參考:深刻理解HDFS工作機制

參考資料:

HDFS官方文檔:http://hadoop.apache.org/docs/stable2/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM