1. 程式人生 > 實用技巧 >HDFS基礎知識點總結

HDFS基礎知識點總結

更多好文可微信搜尋關注公眾號:知了小巷
公眾號後臺回覆資料,可領取2020大資料學習大禮包

1. HDFS讀寫流程

寫資料流程

  1. 客戶端Client通過Distributed FileSystem模組向NameNode節點發出上傳檔案請求,NameNode檢查目標檔案是否已經存在以及父目錄是否存在;
  2. NameNode返回是否可以上傳,如果不能上傳則返回異常。
  3. 確定可以上傳,客戶端請求第一個block上傳到哪幾個DataNode伺服器上。
  4. NameNode返回3個DataNode節點(有兩個副本、且遵循機架或資料中心感應原則),假定為dn1、dn2、dn3。
  5. 客戶端通過FSDataOutputStream模組請求dn1上傳資料,dn1收到請求會繼續呼叫dn2,然後dn2呼叫dn3,將這個通訊管道(Pipeline of DataNodes)建立完成。
  6. dn1、dn2、dn3逐級應答客戶端。
  7. 客戶端開始往dn1上傳第一個block(先從磁碟讀取資料放到一個本地記憶體快取),以packet(64KB)為單位,dn1收到一個packet就會傳給dn2,dn2收到後傳給dn3;dn1每傳一個packet就會放入一個應答佇列等待應答。
  8. 當一個block傳輸完成之後,客戶端再次請求NameNode上傳第二個block的伺服器。(重複執行3~7步)

讀資料流程

  1. 客戶端Client首先呼叫FileSystem.open()方法,獲取到DistributedFileSystem例項。
  2. DistributedFileSystem向NameNode發起RPC(遠端過程呼叫)請求獲取檔案的開始部分或全部block列表,對於每個返回的塊,都包含該塊所在的DataNode地址。這些DataNode會按照Hadoop定義的叢集拓撲結構得出客戶端的距離,然後再進行排序。如果客戶端本身就是一個DataNode,那麼將從本地讀取檔案。
  3. DistributedFileSystem會向客戶端Client返回一個支援檔案定位的輸入流物件FSDataInputStream,用於客戶端讀取資料。FSDataInputStream包含一個DFSInputStream物件,這個物件用來管理DataNode和NameNode之間的IO。
  4. 客戶端呼叫read()方法,DFSInputStream就會找出距離客戶端最近的DataNode並連線DataNode。
  5. DFSInputStream物件中包含檔案開始部分的資料塊所在的DataNode地址,首先它會連線包含檔案第一個塊最近的DataNode。隨後,在資料流中重複呼叫read()方法,直到這個塊全部讀完為止。如果第一個block塊的資料讀完,就會關閉指向第一個block塊的DataNode連線,接著讀取下一個block塊。
  6. 如果第一批block都讀完了,DFSInputStream就會去NameNode拿下一批blocks的location,然後繼續讀,如果所有block塊都讀完,這時就會關閉掉所有的流。

    需要注意的是:
    read()方法是並行讀取block資料,不是一塊接著一塊的讀取;NameNode只是返回Client請求包含塊的DataNode地址,並不是返回請求塊的資料。最終讀取來所有的block會合併成一個完整的最終檔案。

2. HDFS中NameNode和DataNode的作用?

NameNode

NameNode理解為Master-Slave架構中的Master,是叢集管理者。NameNode是HDFS叢集的元資料節點,叢集中只能有一個Active的NameNode對外提供服務。

  1. 管理HDFS的名稱空間(檔案目錄樹):HDFS很方便的一點就是對於使用者來說很友好,使用者不需要考慮具體實現細節,看到的目錄結構和使用的Linux或類Unix檔案系統類似。
  2. 管理資料塊block對映資訊及副本資訊;一個檔案對應的塊的名字以及塊被儲存在什麼位置,還有每一個檔案備份多少都是由NameNode來管理。
  3. 處理客戶端讀寫請求。

DataNode

DataNode理解為Master-Slave架構中的Slave,是HDFS叢集實際儲存資料塊的節點,NameNode下達命令,DataNode執行實際的資料讀寫操作。

  1. 儲存實際的資料塊。
  2. 執行資料塊的讀寫操作。

3. SecondaryNameNode的作用?或者NameNode的啟動過程?

SecondaryNameNode有兩個作用,一是映象備份;二是日誌與映象的定期合併,即合併NameNode的edit logs到fsimage檔案中。

第一階段 NameNode啟動

  1. 第一次啟動NameNode格式化後,建立fsimage和edits檔案。如果不是第一次啟動,直接載入編輯日誌和映象檔案到記憶體。
  2. 客戶端對元資料進行增刪改的請求。
  3. NameNode記錄操作日誌,更新滾動日誌。
  4. NameNode在記憶體中對資料進行增刪改查。

第二階段 SecondaryNameNode參與工作

SecondaryNameNode詢問NameNode是否需要Checkpoint。直接帶回NameNode是否要做Checkpoint的結果。
(Checkpoint的判斷條件:① 定時時間到,預設1小時 ② edits中的操作次數已滿,預設100萬)

  1. SecondaryNameNode請求執行Checkpoint。
  2. NameNode滾動正在寫的edits日誌。
  3. 將滾動前的編輯日誌和映象檔案拷貝到SecondaryNameNode。
  4. SecondaryNameNode載入編輯日誌和映象檔案到記憶體,並進行合併。
  5. 生成新的映象檔案fsimage.chkpoint。
  6. 拷貝fsimage.chkpoint到NameNode。
  7. NameNode將fsimage.chkpoint重新命名成fsimage。

    注意:SecondaryNameNode不是NameNode的備份節點,NameNode掛了,SecondaryNameNode頂不上去的。

web端訪問SecondaryNameNode

  1. 啟動叢集
    瀏覽器中輸入:http://xxxxx:50090/status.html
    Hadoop3.x預設埠號是9868
  2. 頁面可以檢視SecondaryNameNode的資訊

4. 什麼情況下HDFS叢集會進入安全模式?有哪些解決辦法?

  1. 進入安全模式的情況:

    叢集啟動時必定會進入安全模式:
    需要注意:如果滿足“最小副本條件”,NameNode會在30秒鐘之後就退出安全模式。所謂的最小副本條件指的是在整個檔案系統中99.9%的塊滿足最小副本級別(預設值:dfs.replication.min=1)。在啟動一個剛剛格式化的HDFS叢集時,因為系統中還沒有任何塊,所以NameNode不會進入安全模式。
    NameNode啟動時,首先將映象檔案fsimage載入記憶體,並執行編輯日誌edits中的各項操作。一旦在記憶體中成功建立檔案系統元資料的映象,則建立一個新的fsimage檔案和一個空的編輯日誌。此時,NameNode開始監聽DataNode請求。但是此刻,NameNode執行在安全模式,即NameNode的檔案系統對於客戶端來說是隻讀的。
    HDFS系統中的資料塊的位置並不是由NameNode維護的,而是以塊列表的形式儲存在DataNode中。在安全模式下,各個DataNode會向NameNode傳送最新的塊列表資訊,NameNode瞭解到足夠多的塊位置資訊之後,即可高效執行檔案系統。 在系統的正常操作期間,NameNode會在記憶體中保留所有塊位置的對映資訊。

  2. 異常情況下導致的安全模式

    原因:block資料塊確實有缺失,當NameNode發現叢集中的block資料塊丟失數量達到一個閾值時,NameNode就會進入安全模式狀態,不再接收客戶端的資料更新操作。

解決辦法

  1. 調低進入安全模式的閾值
    hdfs-site.xml配置檔案中:

    1
    2
    <name>dfs.namenode.safemode.threshold-pct</name>
    <value>0.999f</value>
  2. 強制離開

    1
    hdfs dfsadmin-safemode leave
  3. 重新格式化叢集

  4. 修復損壞的塊檔案

dfsadmin操作語法

叢集處於安全模式下,不能執行重要操作(寫操作)。叢集啟動完成後,自動退出安全模式。

檢視安全模式下的狀態

hdfs dfsadmin -safemode get

進入安全模式狀態

hdfs dfsadmin -safemode enter

離開安全模式狀態

hdfs dfsadmin -safemode leave

等待安全模式狀態

hdfs dfsadmin -safemode wait

5. 為什麼HDFS不適合儲存小檔案?

HDFS天生就是為儲存大檔案而生的,一個塊的元資料大小大概在150位元組左右,儲存一個小檔案就要佔用NameNode 150位元組的記憶體,如果儲存大量的小檔案,很快就會將NameNode的記憶體耗盡,而整個叢集儲存的資料量卻很小,失去了HDFS的意義,同時也會影響NameNode的定址時間,導致定址時間過長。
可以將大量小檔案預先合併後再上傳,或者將檔案以append的形式追加在HDFS檔案末尾。

6. HDFS支援的儲存格式和壓縮演算法?

  1. 儲存格式

    SequenceFile
    SequenceFile是以二進位制鍵值對的形式儲存資料,支援三種記錄儲存方式:
    無壓縮:IO效率較差,和壓縮相比,不壓縮的情況下沒有什麼優勢
    記錄級壓縮:對每條記錄都壓縮,這種壓縮效率比較一般
    塊級壓縮:這裡的塊不同於HDFS中的塊的概念,這種方式會將達到指定塊大小的二進位制資料壓縮為一個塊。

    Avro
    將資料定義和資料一起儲存在一條訊息中,其中資料定義是以JSON格式進行儲存,資料是以二進位制格式儲存。Avro標記用於將大型資料集分割成適合MapReduce處理的子資料集。

    RCFile
    升級版ORC。以列格式儲存每個行組資料。它不是儲存第一行然後是第二行,而是儲存所有行上的第一列,然後是所有行上的第二列,以此類推。

    Parquet
    Parquet是Hadoop的一種列式儲存格式,提供了高效的編碼和壓縮方案。

  2. 壓縮演算法

    Gzip壓縮
    優點:壓縮比率高,而且壓縮/解壓縮速度也比較塊;Hadoop本身預設支援,在應用中處理Gzip格式的檔案和直接處理普通文字一樣;大部分Linux系統都自帶gzip命令,使用比較方便。
    缺點:不支援資料分片split。
    應用場景:當每個檔案壓縮之後在130M以內的(一個塊大小內),都可以考慮使用Gzip壓縮格式。

    Bzip壓縮
    優點:支援split;具有很高壓縮率,比Gzip壓縮率還要高;Hadoop本身預設支援,但不支援Native;在Linux系統下自帶bzip2命令,使用方便。
    缺點:壓縮/解壓縮速度慢;不支援Native。
    應用場景:適合對速度要求不高,但需要較高的壓縮率的時候,可以作為MapReduce作業的輸出格式;或者輸出之後的資料比較大,處理之後的資料需要壓縮存檔,減少磁碟空間並且以後資料用得比較少的情況;或者對單個很大的文字檔案想壓縮減少儲存空間,同時又支援split,而且相容之前的應用程式(應用程式不需要改動)的情況。

    Lzo壓縮
    優點:壓縮/解壓縮速度也比較快,合理的壓縮率;支援split,是Hadoop中最流行的壓縮格式;可以在Linux系統下安裝lzop命令,使用方便。
    缺點:壓縮率比Gzip要低一些;Hadoop本身不支援,需要安裝。在應用中對lzo格式的檔案需要做一些特殊處理(為了支援split需要建立索引,還需要指定inputformat為lzo格式)。
    應用場景:一個很大的文字檔案,壓縮之後還大於200M以上的可以考慮,而且單個檔案越大,lzo優點越明顯。

    Snappy壓縮
    優點:高壓縮速度和合理的壓縮率。
    缺點:不支援split;壓縮率比Gzip要低;Hadoop本身不支援,需要安裝。
    應用場景:當MapReduce作業的Map輸出的資料比較大的時候,作為Map到Reduce的中間資料的壓縮格式;或者作為一個MapReduce作業的輸出和另外一個MapReduce作業的輸入。
    一般Lzo和Snappy用的比較多,Snappy不是CDH自帶的。

7. HDFS的可靠性策略

  1. 檔案完整性

    • 在HDFS檔案建立時,每個資料塊都會產生校驗和,校驗和會儲存在.meta檔案裡面。
    • 客戶端獲取資料的時候可以檢查校驗和是否相同,從而發現數據塊是否損壞。
    • 如果正在讀取的資料庫損壞,則可以繼續讀取其它的副本資料。NameNode標記該塊已經損壞,然後複製block達到預期設定的檔案備份數。
    • DataNode在其檔案建立後三週驗證其checksum。
  1. 網路或者機器失效

    • 副本冗餘。
    • 機架感知策略(副本放置策略)。
    • 心跳機制策略。
  1. Active NameNode掛掉

    • 主備切換(HA高可用,1個Active,1或多個Standby)
    • 映象檔案和操作日誌磁碟儲存
    • 映象檔案和操作日誌可以儲存多份,多磁碟儲存(JournalNode)
  1. 其他保障可靠性機制

    • 快照(儲存了HDFS系統某一時刻的影像,可以還原到該時刻)
    • 回收站機制。(.trash 重要!)
    • 安全模式

8. HDFS的優缺點

  1. HDFS優點

    • 高容錯性:資料自動儲存多個副本,副本丟失以後,會自動恢復。
    • 適合批處理:移動計算而非資料、把資料位置暴露給計算框架。
    • 適合大規模資料處理:GB、TB、甚至PB級資料、百萬規模以上的檔案數量,1000以上節點規模。
    • 流式檔案訪問:一次寫入,多次讀取;保證資料一致性。
    • 可構建在廉價機器上:通過多副本提高可靠性,提供了容錯和恢復機制。
  2. HDFS缺點

    • 不適合低延遲資料訪問:比如毫秒級、低延遲與高吞吐率。
    • 不適合小檔案存取:佔用NameNode大量記憶體,尋道時間超過讀取時間。
    • 不適合併發寫入、檔案隨機修改;一個檔案只能有一個寫者,僅支援append。

9. DataNode宕機後,叢集能否立即下線DataNode?DataNode下線之後,叢集會做哪些工作?

不能立即下線,預設需要等待10分30秒。
DataNode下線之後,叢集會複製下線的DataNode管理的資料塊。

10. 重新格式化NameNode以後,使用start-dfs.sh啟動叢集,DataNode能正常啟動嗎?為什麼?

不能,NameNode重新格式化之後,clusterid發生改變,而DataNode節點還儲存著原來的clusterid。

11. DataNode在什麼情況下不會備份?

DataNode在強制關閉或者非正常斷電的情況下不會備份。

12. 叢集中其中一個DataNode出現錯誤會怎麼樣?

這個出錯的DataNode管理的資料會在其他正常DataNode上重新做備份。

13. 一個DataNode宕機了,怎會恢復?

將DataNode節點的資料刪除,重新當成新節點加入叢集即可。

HDFS cluster primarily consists of a NameNode that manages the file system Metadata and a DataNodes that stores the actual data.

附:HDFS寫資料流程圖12步

  1. A client initiates write operation by calling ‘create()’ method of DistributedFileSystem object which creates a new file - Step no. 1 in the above diagram.
  2. DistributedFileSystem object connects to the NameNode using RPC call and initiates new file creation. However, this file creates operation does not associate any blocks with the file. It is the responsibility of NameNode to verify that the file (which is being created) does not exist already and a client has correct permissions to create a new file. If a file already exists or client does not have sufficient permission to create a new file, then IOException is thrown to the client. Otherwise, the operation succeeds and a new record for the file is created by the NameNode.
  3. Once a new record in NameNode is created, an object of type FSDataOutputStream is returned to the client. A client uses it to write data into the HDFS. Data write method is invoked (step 3 in the diagram).
  4. FSDataOutputStream contains DFSOutputStream object which looks after communication with DataNodes and NameNode. While the client continues writing data, DFSOutputStream continues creating packets with this data. These packets are enqueued into a queue which is called as DataQueue.
  5. There is one more component called DataStreamer which consumes this DataQueue. DataStreamer also asks NameNode for allocation of new blocks thereby picking desirable DataNodes to be used for replication.
  6. Now, the process of replication starts by creating a pipeline using DataNodes. In our case, we have chosen a replication level of 3 and hence there are 3 DataNodes in the pipeline.
  7. The DataStreamer pours packets into the first DataNode in the pipeline.
  8. Every DataNode in a pipeline stores packet received by it and forwards the same to the second DataNode in a pipeline.
  9. Another queue, ‘Ack Queue’ is maintained by DFSOutputStream to store packets which are waiting for acknowledgment from DataNodes.
  10. Once acknowledgment for a packet in the queue is received from all DataNodes in the pipeline, it is removed from the ‘Ack Queue’. In the event of any DataNode failure, packets from this queue are used to reinitiate the operation.
  11. After a client is done with the writing data, it calls a close() method (Step 9 in the diagram) Call to close(), results into flushing remaining data packets to the pipeline followed by waiting for acknowledgment.
  12. Once a final acknowledgment is received, NameNode is contacted to tell it that the file write operation is complete.

附:HDFS讀資料流程圖7步

  1. A client initiates read request by calling ‘open()’ method of FileSystem object; it is an object of type DistributedFileSystem.
  2. This object connects to namenode using RPC and gets metadata information such as the locations of the blocks of the file. Please note that these addresses are of first few blocks of a file.
  3. In response to this metadata request, addresses of the DataNodes having a copy of that block is returned back.
  4. Once addresses of DataNodes are received, an object of type FSDataInputStream is returned to the client. FSDataInputStream contains DFSInputStream which takes care of interactions with DataNode and NameNode. In step 4 shown in the above diagram, a client invokes ‘read()’ method which causes DFSInputStream to establish a connection with the first DataNode with the first block of a file.
  5. Data is read in the form of streams wherein client invokes ‘read()’ method repeatedly. This process of read() operation continues till it reaches the end of block.
  6. Once the end of a block is reached, DFSInputStream closes the connection and moves on to locate the next DataNode for the next block
  7. Once a client has done with the reading, it calls a close() method.