Hadoop面試複習系列——HDFS(一)

  • 2019 年 10 月 30 日
  • 筆記

轉載自: https://cloud.tencent.com/developer/article/1031641 https://my.oschina.net/freelili/blog/1853668

HDFS優缺點

  1. 優點
  • 1.1 高容錯性
    • 可以由數百或數千個伺服器機器組成,每個伺服器機器存儲文件系統數據的一部分;
    • 數據自動保存多個副本;
    • 副本丟失後檢測故障快速,自動恢復。
  • 1.2 適合批處理
    • 移動計算而非數據;
    • 數據位置暴露給計算框架;
    • 數據訪問的高吞吐量;
    • 運行的應用程式對其數據集進行流式訪問。
  • 1.3 適合大數據處理
    • 典型文件大小為千兆位元組到太位元組;
    • 支援單個實例中的數千萬個文件;
    • 10K+節點。
  • 1.4 可構建在廉價的機器上
    • 通過多副本提高可靠性;
    • 提供了容錯與恢復機制。
  • 1.5 跨異構硬體和軟體平台的可移植性強
    • 輕鬆地從一個平台移植到另一個平台。
  • 1.6 簡單一致性模型
    • 應用程式需要一次寫入多次讀取文件的訪問模型;
    • 除了追加和截斷之外,不需要更改已創建,寫入和關閉的文件;
    • 簡化了數據一致性問題,並實現了高吞吐量數據訪問;
    • 高度可配置,具有非常適合於許多安裝的默認配置。大多數時候,只需要為非常大的集群調整配置。
  1. 缺點
  • 2.1 不適合低延遲的數據訪問
    • HDFS設計更多的是批處理,而不是用戶交互使用。重點在於數據訪問的高吞吐量,而不是數據訪問的低延遲。
  • 2.2 不適合小文件存取
    • 佔用NameNode大量記憶體;
    • 尋道時間超過讀取時間。
  • 2.3 無法並發寫入、文件隨即修改
    • 一個文件只能有一個寫者;
    • 僅支援追加和截斷。

基本組成

  1. Namenode
  • 接受客戶端的讀寫服務 執行文件系統命名空間操作,如打開,關閉和重命名文件和目錄。
  • 管理文件系統命名空間 記錄對文件系統命名空間或其屬性的任何更改。
  • 存儲元數據資訊—metadata Metadata是存儲在Namenode上的元數據資訊,它存儲到磁碟的文件名為:fsimage。並且有個叫edits的文件記錄對metadata的操作日誌。總體來說,fsimage與edits文件記錄了Metadata中的許可權資訊和文件系統目錄樹、文件包含哪些塊、確定塊到DataNode的映射、Block存放在哪些DataNode上(由DataNode啟動時上報)。 NameNode將這些資訊載入到記憶體並進行拼裝,就成為了一個完整的元數據資訊。Namenode在記憶體中保存著整個文件系統的命名空間和文件數據塊映射(Blockmap)的映像。這個關鍵的元數據結構設計得很緊湊,因而一個有4G記憶體的Namenode足夠支撐大量的文件和目錄。當Namenode啟動時,它從硬碟中讀取Edits和FsImage,將所有Edits中的事務作用在記憶體中的FsImage上,並將這個新版本的FsImage從記憶體中保存到本地磁碟上,然後刪除舊的Edits,因為這箇舊的Edits的事務都已經作用在FsImage上了。這個過程稱為一個檢查點(checkpoint)。 Datanode將HDFS數據以文件的形式存儲在本地的文件系統中,它並不知道有關HDFS文件的資訊。它把每個HDFS數據塊存儲在本地文件系統的一個單獨的文件中。Datanode並不在同一個目錄創建所有的文件,實際上,它用試探的方法來確定每個目錄的最佳文件數目,並且在適當的時候創建子目錄。在同一個目錄中創建所有的本地文件並不是最優的選擇,這是因為本地文件系統可能無法高效地在單個目錄中支援大量的文件。當一個Datanode啟動時,它會掃描本地文件系統,產生一個這些本地文件對應的所有HDFS數據塊的列表,然後作為報告發送到Namenode,這個報告就是塊狀態報告。
  • 管理文件系統命名空間 HDFS支援傳統的分層文件組織。用戶或應用程式可以在這些目錄中創建目錄和存儲文件。文件系統命名空間層次結構與大多數其他現有文件系統類似:可以創建和刪除文件,將文件從一個目錄移動到另一個目錄,或重命名文件。HDFS支援用戶配額和訪問許可權。但不支援硬鏈接或軟鏈接。 NameNode維護文件系統命名空間。對文件系統命名空間或其屬性的任何更改由NameNode記錄。應用程式可以指定應由HDFS維護的文件的副本數。文件的副本數稱為該文件的複製因子。此資訊由NameNode存儲。
  1. SecondaryNameNode 它不是NameNode的備份,但可以作為NameNode的備份,當因為斷電或伺服器損壞的情況,可以用SecondNameNode中已合併的fsimage文件作為備份文件恢復到NameNode上,但是很有可能丟失掉在合併過程中新生成的edits資訊。因此不是完全的備份。 由於NameNode僅在啟動期間合併fsimage和edits文件,因此在繁忙的群集上,edits日誌文件可能會隨時間變得非常大。較大編輯文件的另一個副作用是下一次重新啟動NameNode需要更長時間。SecondNameNode的主要功能是幫助NameNode合併edits和fsimage文件,從而減少NameNode啟動時間
  • SNN執行合併時機 根據配置文件配置的時間間隔fs.checkpoint.period默認1小時; dfs.namenode.checkpoint.txns,默認設置為1百萬,也就是Edits中的事務條數達到1百萬就會觸發一次合併,即使未達到檢查點期間。
  • SNN合併流程

snn合併流程.png

  • 首先生成一個名叫edits.new的文件用於記錄合併過程中產生的日誌資訊;
  • 當觸發到某一時機時(時間間隔達到1小時或Edits中的事務條數達到1百萬)時SecondaryNamenode將edits文件、與fsimage文件從NameNode上讀取到SecondNamenode上;
  • 將edits文件與fsimage進行合併操作,合併成一個fsimage.ckpt文件;
  • 將生成的合併後的文件fsimage.ckpt文件轉換到NameNode上;
  • 將fsimage.ckpt在NameNode上變成fsimage文件替換NameNode上原有的fsimage文件,並將edits.new文件上變成edits文件替換NameNode上原有的edits文件。
  • SNN在hadoop2.x及以上版本在非高可用狀態時還存在,但是在hadoop2.x及以上版本高可用狀態下SNN就不存在了,在hadoop2.x及以上版本在高可用狀態下,處於standby狀態的NameNode來做合併操作。
  1. DataNode 管理附加到它們運行的節點的存儲,並允許用戶數據存儲在文件中; 在內部,文件被分割成一個或多個塊(Block),並且這些塊被存儲在一組DataNode中; 負責提供來自文件系統客戶端的讀取和寫入請求; 執行塊創建,刪除; 啟動DN進程的時候會向NN彙報Block資訊; 通過向NN發送心跳保持與其聯繫(3秒一次),如果NN10分鐘沒有收到DN的心跳,則認為DN已經丟失,並且複製其上的Block到其他的DN上。
  • HDFS存儲單元(block)
    • 文件被切分成固定大小的數據塊 默認數據塊大小為64MB(hadoop1.x)、128MB(hadoop2.x)、256MB(hadoop3.x),可配置; 若文件大小不到一個塊大小,則單獨存成一個block,block塊是一個邏輯意義上的概念。文件大小是多少,就佔多少空間。
    • 一個文件存儲方式 按大小被切分成不同的block,存儲到不同的節點上; 默認情況下,每個block都有3個副本; block大小與副本數通過client端上傳文件時設置,文件上傳成功後副本數可以變更,block size不可變更。 將大文件拆分成256MB的block塊,每個block塊分別隨機存放在不同的節點上,從而避免了數據傾斜的問題,但是在開發過程中,如果演算法、程式寫的不好,同樣也會出現數據傾斜的問題。
  • 數據複製
    • 數據複製概述 HDFS被設計成能夠在一個大集群中跨機器可靠地存儲超大文件。它將每個文件存儲成一系列的數據塊,除了最後一個,所有的數據塊都是同樣大小的。為了容錯,文件的所有數據塊都會有副本。每個文件的數據塊大小和副本係數都是可配置的。應用程式可以指定某個文件的副本數目。副本係數可以在文件創建的時候指定,也可以在之後改變。HDFS中的文件都是一次性寫入的,並且嚴格要求在任何時候只能有一個寫入者。 Namenode全權管理數據塊的複製,它周期性地從集群中的每個Datanode接收心跳訊號和塊狀態報告(Blockreport)。接收到心跳訊號意味著該Datanode節點工作正常。塊狀態報告包含了一個該Datanode上所有數據塊的列表。
    • Block的副本放置策略 副本的存放是HDFS可靠性和性能的關鍵。 在大多數情況下,副本係數是3,HDFS的存放策略是將一個副本存放在本地機架的節點上,一個副本放在同一機架的另一個節點上,最後一個副本放在不同機架的節點上。這種策略減少了機架間的數據傳輸,這就提高了寫操作的效率。機架的錯誤遠遠比節點的錯誤少,所以這個策略不會影響到數據的可靠性和可用性。於此同時,因為數據塊只放在兩個(不是三個)不同的機架上,所以此策略減少了讀取數據時需要的網路傳輸總頻寬。在這種策略下,副本並不是均勻分布在不同的機架上。三分之一的副本在一個節點上,三分之二的副本在一個機架上,其他副本均勻分布在剩下的機架中,這一策略在不損害數據可靠性和讀取性能的情況下改進了寫的性能。
  • 副本選擇 為了降低整體的頻寬消耗和讀取延時,HDFS會盡量讓讀取程式讀取離它最近的副本。其計算方式大致如下:
    1. 相同節點 = 0
    2. 相同機架不同節點 = 2
    3. 相同數據中心不同機架 = 4
    4. 不同數據中心 = 6

    如果在讀取程式的同一個機架上有一個副本,那麼就讀取該副本。如果一個HDFS集群跨越多個數據中心,那麼客戶端也將首先讀本地數據中心的副本。

  • 安全模式 NameNode在啟動的時候會進入一個稱為安全模式的特殊狀態,它首先將映像文件(fsimage)載入記憶體,並執行編輯日誌(edits)中的各項操作;一旦在記憶體中成功建立文件系統元數據映射,則創建一個新的fsimage文件(這個操作不需要SecondNameNode來做)與一個空的編輯日誌; 此刻namenode運行在安全模式,即namenode的文件系統對於客戶端來說是只讀的,顯示目錄、顯示文件內容等,寫、刪除、重命名都會失敗; 在此階段namenode搜集各個datanode的報告,當數據塊達到最小副本數以上時,會被認為是「安全」的,在一定比例的數據塊被認為是安全的以後(可設置),再過若干時間,安全模式結束; 當檢測到副本數不足數據塊時,該塊會被複制,直到達到最小副本數,系統中數據塊的位置並不是由namenode維護的,而是以塊列表形式存儲在datanode中。 特別的–當namenode節點的磁碟滿了,HDFS也會進入安全模式,並且此時無法退出安全模式
  • 數據組織
    • 數據塊 HDFS被設計成支援大文件,適用HDFS的是那些需要處理大規模的數據集的應用。這些應用都是只寫入數據一次,但卻讀取一次或多次,並且讀取速度應能滿足流式讀取的需要。HDFS支援文件的「一次寫入多次讀取」語義。一個典型的數據塊大小是256MB。因而,HDFS中的文件總是按照256M被切分成不同的塊,每個塊儘可能地存儲於不同的Datanode中。
    • 分段 客戶端創建文件的請求其實並沒有立即發送給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複製到下一個。 如果複製過程中某個DataNode出現問題,並不會導致該次寫入過程失敗,問題DataNode將排出這個管道,其他節點正常寫入,只要有(dfs.namenode.repliction.min 默認為1),個節點寫入成功,那麼本次寫入過程就是成功的。後續 NameNode 在檢查文件副本數的時候,會幫助恢復正常

讀寫流程

  • 讀數據流程
hdfs讀數據流程.jpg
  • 使用HDFS提供的客戶端Client, 通過 DistributedFileSystem 向遠程的Namenode發起RPC請求;
  • Namenode會視情況返迴文件的部分或者全部block列表, 對於每個block, Namenode都會返回有該block副本的DataNode地址;
  • 客戶端Client會選取離客戶端最近的DataNode來讀取block; 如果客戶端本身就是DataNode, 那麼將從本地直接獲取數據;
  • 讀取完當前block的數據後, 關閉當前的DataNode鏈接, 並為讀取下一個block尋找最佳的DataNode;
  • 當讀完列表block後, 且文件讀取還沒有結束, 客戶端會繼續向Namenode獲取下一批的block列表;
  • 以上這些步驟對於客戶端來說都是透明的。客戶端只需通過 DistributedFileSystem 返回的 FSDataInputStream 讀取數據即可
  • 特別的–如果客戶端和所連接的DataNode在讀取時出現故障,那麼它就會去嘗試連接存儲這個塊的下一個最近的DataNode,同時它會記錄這個節點的故障,以免後面再次連接該節點。客戶端還會驗證從DataNode傳送過來的數據校驗和。如果發現一個損壞塊,那麼客戶端將再嘗試從別的DataNode讀取數據塊,並且會告訴NameNode 這個資訊,NameNode也會更新保存的文件資訊,進行數據修復。
  • 寫數據流程
hdfs寫流程.jpg
  • 客戶端調用create來新建文件。
  • DistributedFileSystem 通過RPC調用在 NameNode 的文件系統命名空間中創建一個後綴是.copy新文件,此時還沒有相關的DataNode與之相關。
  • NameNode 會通過多種驗證保證新的文件不存在文件系統中,並且確保請求客戶端擁有創建文件的許可權。當所有驗證通過時,NameNode 會創建一個新文件的記錄,如果創建失敗,則拋出一個IOException異常;如果成功 namenode 能夠掌握集群DataNode整體狀況,並將第一批 block 塊分配數據塊後,連同 DataNode 列表資訊返回給客戶端;
  • 當客戶端寫入數據時,DFSOutputStream 會將文件分割成數據包(64k),然後放入一個內部隊列,我們稱為「數據隊列(data queue)」。DataStreamer會將這些小的文件包放入數據流中,DataStreamer的作用是請求NameNode為新的文件包分配合適的DataNode存放副本。返回的DataNode列表形成一個「管道」,假設這裡的副本數是3,那麼這個管道中就會有3個DataNode。DataStreamer將文件包以流的方式傳送給隊列中的第一個DataNode。第一個DataNode會存儲這個包,然後將它推送到第二個DataNode中,隨後照這樣進行,直到管道中的最後一個DataNode,這種 pipeline 的方式加快了寫入過程,並隱藏了副本數對客戶端的影響,即 對客戶端來說,副本數是透明的。 副本的放置遵循 Block的副本放置策略
  • DFSOutputStream同時也會保存一個包的內部隊列,用來等待管道中的DataNode返回確認資訊,這個隊列被稱為確認隊列(ask queue)。只有當所有的管道中的DataNode都返回了寫入成功的資訊文件包,才會從確認隊列中刪除。
  • 客戶端完成數據寫入後,對數據流調用close方法。該操作將剩餘的所有數據寫入dataNode管線,當DataNode 向 NameNode 心跳彙報的時候,新寫入的 block 資訊被更新到 NameNode.第一批block 塊的寫入完成
  • 重複以上過程,客戶端繼續第二批 block 塊的寫入,直至最後一批寫入完成結束!
  • 特別的–當出現寫入某個DataNode失敗時,HDFS會作出以下反應: 首先管道會被關閉,任何在 確認隊列 中的文件包都會被添加到數據隊列的前端,以確保故障節點下游的datanode不會漏掉任何一個數據包。 為存儲在另一個正常的datanode的當前數據塊指定一個新的標識,並將標識傳送給nameNode,當dataNode 在恢復後,會發現其原來的標識是過時的,於是就可以刪除存儲的不完整的那部分數據塊。 從管線中刪除故障datanode,基於兩個正常的datanode構建新的管線。餘下的資料庫寫入管線中正常的datanode。 namenode在注意到副本不足時,會在另一個節點上創建一個新的副本。後續的數據塊繼續正常的接受處理。 如果有多個節點的寫入失敗了,如果滿足了最小備份數的設置(dfs.namenode.repliction.min),寫入也將會成功
  • 寫入一致性 新建一個文件後,它能夠在文件系統命名空間中立即可見 寫入文件的內容不保證立即可見(即逝數據流已經調用flush()方法刷新並存儲) 當前正在寫入的塊對其他reader不可見。 通過hflush()方法後,數據被寫入datanode的記憶體中。可保證對所有reader可見 通過hsync()方法後,數據被寫入到磁碟上。 如果沒有調用hflush或者hsync()方法。客戶端在故障的情況下就會存在數據塊丟失