Hadoop(二) HDFS 底層原理解析

目錄

 HDFS概念

HDFS優缺點

優點

缺點

HDFS 架構/角色

Client:客戶端

NameNode:master,它是一個主管、管理者

DataNode

Secondary NameNode

hdfs啓動過程

啓動腳本分析

HDFS啓動過程--源碼分析

HDFS 文件塊大小

HDFS的元數據管理

NameNode 元數據存儲機制

查看編輯日誌

hdfs 不適合存儲小文件

HDFS 輔助功能

心跳機制

安全模式

副本存放策略

負載均衡

HDFS讀寫原理

HDFS寫入文件的過程分析

HDFS讀取文件的過程分析


 HDFS概念

HDFS,它是一個文件系統,用於存儲文件,通過目錄樹來定位文件;其次,它是分佈式的,由很多服務器聯合起來實現其功能,集羣中的服務器有各自的角色。

HDFS的設計適合一次寫入,多次讀出的場景,且不支持文件的修改。適合用來做數據分析,並不適合用來做網盤應用。

 

HDFS優缺點

優點

1)高容錯性

(1)數據自動保存多個副本。它通過增加副本的形式,提高容錯性。

(2)某一個副本丟失以後,它可以自動恢復。

 2)適合大數據處理

(1)數據規模:能夠處理數據規模達到 GB、TB、甚至PB級別的數據。

(2)文件規模:能夠處理百萬規模以上的文件數量,數量相當之大。

 3)流式數據訪問

(1)一次寫入,多次讀取,不能修改,只能追加。

(2)它能保證數據的一致性。

 4)可構建在廉價機器上,通過多副本機制,提高可靠性。

缺點

 1)不適合低延時數據訪問,比如毫秒級的存儲數據,是做不到的。

 2)無法高效的對大量小文件進行存儲

 (1)存儲大量小文件的話,它會佔用 NameNode大量的內存來存儲文件、目錄和塊信息。這樣是不可取的,因爲NameNode的內存總是有限的。

(2)小文件存儲的尋道時間會超過讀取時間,它違反了HDFS的設計目標。

 3)併發寫入、文件隨機修改

(1)一個文件只能有一個寫,不允許多個線程同時寫。

(2)僅支持數據 append(追加),不支持文件的隨機修改。

 

HDFS 架構/角色

Client:客戶端

(1)文件切分。文件上傳 HDFS 的時候,Client 將文件切分成一個一個的Block,然後進行存儲。

(2)與NameNode交互,獲取文件的位置信息。

(3)與DataNode交互,讀取或者寫入數據。

(4)Client提供一些命令來管理HDFS,比如啓動或者關閉HDFS。

(5)Client可以通過一些命令來訪問HDFS。

NameNode:master,它是一個主管、管理者

(1)管理HDFS的名稱空間。

(2)管理數據塊(Block)映射信息

(3)配置副本策略

(4)處理客戶端讀寫請求。

DataNode

Slave節點,NameNode下達命令,DataNode執行實際的操作

 (1)存儲實際的數據塊。

 (2)執行數據塊的讀/寫操作。

Secondary NameNode

並非NameNode的熱備。當NameNode掛掉的時候,它並不能馬上替換NameNode並提供服務

(1)輔助NameNode,分擔其工作量。

(2)定期合併Fsimage和Edits,並推送給NameNode。

(3)在緊急情況下,可輔助恢復NameNode。

 

hdfs啓動過程

啓動腳本分析

start-dfs.sh
            namenode:    //單獨啓動 hadoop-daemon.sh start namenode
                hdfs getconf -namenode    //獲取namenode節點
                hadoop-daemons.sh  --hostnames s101  start namenode ==> hadoop-daemon.sh start namenode

            datanode:    //單獨啓動 hadoop-daemons.sh start datanode
                hadoop-daemons.sh start datanode

            secondarynamenode:    //單獨啓動hadoop-daemon.sh start secondarynamenode
                hdfs getconf -secondarynamenodes 2>/dev/null    //獲取2nn節點地址
                hadoop-daemons.sh --hostnames 0.0.0.0 start secondarynamenode ==> hadoop-daemon.sh start secondarynamenode

啓動namenode
    0)namenode先進入安全模式,在此模式下,文件均處於只讀狀態
    1)namenode將fsimage文件加載到內存
    2)將edits_inprogress實例化爲edits文件
    3)namenode將edits文件加載到內存
    4)將fsimage文件與edits文件進行融合,通過舊的fsimage文件重現edits文件的操作步驟,生成新的fsimage文件
    5)退出安全模式,文件可寫

 

HDFS啓動過程--源碼分析

 

HDFS 文件塊大小

HDFS中的文件在物理上是分塊存儲(block),塊的大小可以通過配置參數( dfs.blocksize)來規定,默認大小在hadoop2.x版本中是128M,老版本中是64M。

HDFS的塊比磁盤的塊大,其目的是爲了最小化尋址開銷。如果塊設置得足夠大,從磁盤傳輸數據的時間會明顯大於定位這個塊開始位置所需的時間。因而,傳輸一個由多個塊組成的文件的時間取決於磁盤傳輸速率。

如果尋址時間約爲10ms,而傳輸速率爲100MB/s,爲了使尋址時間僅佔傳輸時間的1%,我們要將塊大小設置約爲100MB。默認的塊大小128MB

 

HDFS的元數據管理

NameNode 元數據存儲機制


A、內存中有一份完整的元數據(內存 metadata)

B、磁盤有一個“準完整”的元數據鏡像(fsimage)文件(在 namenode 的工作目錄中)

C、用於銜接內存 metadata 和持久化元數據鏡像 fsimage 之間的操作日誌(edits 文件)

(PS:當客戶端對 hdfs 中的文件進行新增或者修改操作,操作記錄首先被記入 edits 日誌 文件中,
      當客戶端操作成功後,相應的元數據會更新到內存 metadata 中)

操作日誌(存放在硬盤中):
    數據歷史操作日誌文件: edits_000000000000000000*, 可通過運算日誌文件算出元數據
                          每次滾動都會產生一些歷史操作日誌文件
    預寫操作日誌文件:edits_inprogress_0000000000000000*(當前正在使用的編輯日誌文件)
磁盤元數據鏡像文件:fsimage_0000000000000000*
    
元數據與操作日誌存在下列關係:
fsimage = 所有的歷史操作日誌文件之和
metadata = 最新fsimage + edits_inprogress_0000000000000000*
metadata = 所有的歷史操作日誌文件之和 + edits_inprogress_0000000000000000*

日誌滾動:
    1.滾動正在使用的編輯日誌edits_inprogress_0000000000000000*, 生成新的歷史操作日誌文件edits_000000000000000000*
      併產生一個新的正在使用的編輯日誌edits_inprogress_0000000000000000*
    2.將所有的歷史操作日誌文件edits_000000000000000000*與正在使用鏡像文件fsimage_0000000000000000* 加載到內存進行合併
      最終產生一個檢查點文件 *.ckpt
    3.將檢查點文件發送到namenode, namenode將其重命名爲新的鏡像文件

查看編輯日誌

 

    edits:編輯日誌
        hdfs oev -i <input> -o <output> -p <processor xml | binary | stats>
        hdfs oev -i edits_0000000000000000011-0000000000000000051 -o ~/edits.xml -p xml
        
        編輯日誌,主要是記錄對hdfs進行的修改
                                ,這個文件每次開機都會生成一個新的edits_progress
        舊的edits_progress用於與fsimage生成新的fsimage文件
        

<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
  <EDITS_VERSION>-63</EDITS_VERSION>
  <RECORD>
    <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
    <DATA>
      <TXID>38233</TXID>
    </DATA>
  </RECORD>
</EDITS>

    fsimage
        hdfs oiv -i <input> -o <output> -p <processor XML | binary | stats>
        hdfs oiv -i fsimage_0000000000000000053 -o ~/image.xml -p XML
        
        鏡像文件,主要是記錄hdfs的文件樹形結構,及文件的元信息
        總共有兩個,一個新的一箇舊的,每次啓動時上次的變成舊的,重新生成一個新的

<?xml version="1.0"?>
<fsimage><NameSection>
<genstampV1>1000</genstampV1>
<genstampV2>4602</genstampV2>
<genstampV1Limit>0</genstampV1Limit>
<lastAllocatedBlockId>1073745405</lastAllocatedBlockId>
<txid>38232</txid></NameSection>
<INodeSection>
<lastInodeId>28077</lastInodeId>
<inode>
	<id>16385</id>
	<type>DIRECTORY</type>
	<name></name>
	<mtime>1571783352984</mtime>
	<permission>centos:supergroup:rwxr-xr-x</permission>
	<nsquota>9223372036854775807</nsquota>
	<dsquota>-1</dsquota>
</inode>

...

<blocks>
	<block>
	<id>1073742492</id>
	<genstamp>1668</genstamp>
	<numBytes>378</numBytes>
	</block>
</blocks>


hdfs 不適合存儲小文件


HDFS集羣的namenode中存儲元數據的信息,元數據的信息主要包括以下3部分:

1)抽象目錄樹
   文件和目錄自身的屬性信息,例如文件名、目錄名、父目錄信息、文件大小、創建時間、修改時間等。

2)文件和數據塊的映射關係,一個數據塊的元數據大小大約是150byte  

3)數據塊的多個副本存儲地
   件內容存儲相關信息,例如文件塊情況、副本個數、每個副本所在的Data Node 信息等
假設元數據的大小是150byte
對於100個1M的小文件其元數據大小是 100 * 150byte, 也就是用了15k才存儲100M的文件
對於1個100M的大文件,其元據大小是150byte, 也就是我只使用了150byte就可以存儲100M的文件
由此可以看出hdfs不適合存儲小文件,存儲小文件就是浪費namenode內存空間,而且也不利於hdfs查找文件

 

HDFS 輔助功能

心跳機制

1、 Hadoop 是 Master/Slave 結構,Master 中有 NameNode 和 ResourceManager,Slave 中有 Datanode 和 NodeManager 

2、 Master 啓動的時候會啓動一個 IPC(Inter-Process Comunication,進程間通信)server 服 務,等待 slave 的鏈接

3、 Slave 啓動時,會主動鏈接 master 的 ipc server 服務,並且每隔 3 秒鏈接一次 master,這 個間隔時間是可以調整的,參數爲 dfs.heartbeat.interval,這個每隔一段時間去連接一次 的機制,我們形象的稱爲心跳。Slave 通過心跳彙報自己的信息給 master,master 也通 過心跳給 slave 下達命令,

4、 NameNode 通過心跳得知 Datanode 的狀態 ,ResourceManager 通過心跳得知 NodeManager 的狀態

5、 如果 master 長時間都沒有收到 slave 的心跳,就認爲該 slave 掛掉了。

最終NameNode判斷一個DataNode死亡的時間計算公式:

timeout = 10 * 心跳間隔時間  + 2 * 檢查一次消耗的時間

心跳間隔時間:dfs.heartbeat.interval 心跳時間:3s,檢查一次消耗的時間:heartbeat.recheck.interval checktime : 5min,最終宕機之後630s後顯示死亡狀態。

 

安全模式

1、HDFS的啓動和關閉都是先啓動NameNode,在啓動DataNode,最後在啓動secondarynamenode。

2、決定HDFS集羣的啓動時長會有兩個因素:

  1)磁盤元數據的大小

  2)datanode的節點個數

 當元數據很大,或者 節點個數很多的時候,那麼HDFS的啓動,需要一段很長的時間,那麼在還沒有完全啓動的時候HDFS能否對外提供服務?

在HDFS的啓動命令start-dfs.sh執行的時候,HDFS會自動進入安全模式

爲了確保用戶的操作是可以高效的執行成功的,在HDFS發現自身不完整的時候,會進入安全模式。保護自己。

在正常啓動之後,如果HDFS發現所有的數據都是齊全的,那麼HDFS會啓動的退出安全模式

3、對安全模式進行測試

安全模式常用操作命令:

hdfs dfsadmin -safemode leave //強制 NameNode 退出安全模式
hdfs dfsadmin -safemode enter //進入安全模式
hdfs dfsadmin -safemode get //查看安全模式狀態
hdfs dfsadmin -safemode wait //等待,一直到安全模式結束

4、安全模式下測試上傳下載,得出結論:

如果一個操作涉及到元數據的修改的話。都不能進行操作,如果一個操作僅僅只是查詢。那是被允許的。所謂安全模式,僅僅只是保護namenode,而不是保護datanode。

 

副本存放策略

第一副本:放置在上傳文件的DataNode上;如果是集羣外提交,則隨機挑選一臺磁盤不太慢、CPU不太忙的節點上;
第二副本:放置在於第一個副本不同的機架的節點上;
第三副本:與第二個副本相同機架的不同節點上;
如果還有更多的副本:隨機放在節點中;



負載均衡

 

HDFS讀寫原理

HDFS寫入文件的過程分析

1、使用 HDFS 提供的客戶端 Client,向遠程的 namenode 發起 RPC 請求

2、namenode 會檢查要創建的文件是否已經存在,創建者是否有權限進行操作,成功則會 爲文件創建一個記錄,否則會讓客戶端拋出異常;

3、當客戶端開始寫入文件的時候,客戶端會將文件切分成多個 packets,並在內部以數據隊列“data queue(數據隊列)”的形式管理這些 packets,並向 namenode 申請 blocks,獲 取用來存儲 replicas 的合適的 datanode 列表,列表的大小根據 namenode 中 replication 的設定而定;

每個packet大小 = 33byte(頭) + 504byte(126個校驗和空間) + 63K(126個chunk) < 64K---packet取值64k

      

4、開始以 pipeline(管道)的形式將 packet 寫入所有的 replicas 中。客戶端把 packet 以流的 方式寫入第一個 datanode,該 datanode 把該 packet 存儲之後,再將其傳遞給在此 pipeline 中的下一個 datanode,直到最後一個 datanode,這種寫數據的方式呈流水線的形式。

5、最後一個 datanode 成功存儲之後會返回一個 ack packet(確認隊列),在 pipeline 裏傳遞 至客戶端,在客戶端的開發庫內部維護着"ack queue",成功收到 datanode 返回的 ack packet 後會從"data queue"移除相應的 packet。

6、如果傳輸過程中,有某個 datanode 出現了故障,那麼當前的 pipeline 會被關閉,出現故 障的 datanode 會從當前的 pipeline 中移除,剩餘的 block 會繼續剩下的 datanode 中繼續 以 pipeline 的形式傳輸,同時 namenode 會分配一個新的 datanode,保持 replicas 設定的 數量。

7、客戶端完成數據的寫入後,會對數據流調用 close()方法,關閉數據流;

8、只要寫入了 dfs.replication.min(最小寫入成功的副本數)的複本數(默認爲 1),寫操作 就會成功,並且這個塊可以在集羣中異步複製,直到達到其目標複本數(dfs.replication 的默認值爲 3),因爲 namenode 已經知道文件由哪些塊組成,所以它在返回成功前只需 要等待數據塊進行最小量的複製。

 

HDFS讀取文件的過程分析

1、客戶端調用FileSystem 實例的open 方法,獲得這個文件對應的輸入流InputStream。

2、通過RPC 遠程調用NameNode ,獲得NameNode 中此文件對應的數據塊保存位置,包括這個文件的副本的保存位置( 主要是各DataNode的地址) 。

3、獲得輸入流之後,客戶端調用read 方法讀取數據。選擇最近的DataNode 建立連接並讀取數據。

4、如果客戶端和其中一個DataNode 位於同一機器(比如MapReduce 過程中的mapper 和reducer),那麼就會直接從本地讀取數據。

5、到達數據塊末端,關閉與這個DataNode 的連接,然後重新查找下一個數據塊。

6、不斷執行第2 - 5 步直到數據全部讀完。

7、客戶端調用close ,關閉輸入流DFS InputStream。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章