03.03 什麼是HDFS?算了,告訴你也不懂

一、HDFS介紹

隨著數據量越來越大,在一臺機器上已經無法存儲所有的數據了,那我們會將這些數據分配到不同的機器來進行存儲,但是這就帶來一個問題:

不方便管理和維護

所以,我們就希望有一個系統可以將這些分佈在不同操作服務器上的數據進行 統一管理 ,這就有了 分佈式文件系統

  • HDFS 是分佈式文件系統的其中一種(目前用得最廣泛的一種)

在使用HDFS的時候是非常簡單的:雖然HDFS是將文件存儲到不同的機器上,但是我去使用的時候是把這些文件 當做 是存儲在一臺機器的方式去使用(背後卻是多臺機器在執行):

  • 好比:我調用了一個RPC接口,我給他參數,他返回一個response給我。RPC接口做了什麼事其實我都不知道的(可能這個RPC接口又調了其他的RPC接口)----- 屏蔽掉實現細節,對用戶友好
什麼是HDFS?算了,告訴你也不懂

明確一下:HDFS就是一個 分佈式文件系統 ,一個文件系統,我們用它來做什麼? 存數據呀

下面,我們來了解一下HDFS的一些知識,能夠幫我們更好地去「使用」HDFS

二、HDFS學習

從上面我們已經提到了,HDFS作為一個分佈式文件系統,那麼 它的數據是保存在多個系統上的 。例如,下面的圖:一個1GB的文件,會被 切分 成幾個小的文件,每個服務器都會存放一部分。

什麼是HDFS?算了,告訴你也不懂

那肯定會有人會問:那會切分多少個小文件呢?默認以 128MB 的大小來切分,每個 128MB 的文件,在HDFS叫做 (block)

PS:老版本默認是64MB

一個用戶發出了一個 1GB 的文件請求給HDFS客戶端,HDFS客戶端會根據配置(現在默認是 128MB ),對這個文件進行切分,所以HDFS客戶端會切分為8個文件(也叫做 block ),然後每個服務器都會存儲這些切分後的文件(block)。現在我們假設 每個服務器都存儲兩份

什麼是HDFS?算了,告訴你也不懂

這些存放 真實數據 的服務器,在HDFS領域叫做 DataNode

什麼是HDFS?算了,告訴你也不懂

現在問題來了,HDFS客戶端按照配置切分完以後,怎麼知道往哪個服務器(DataNode)放數據呢?這個時候,就需要另一個角色了,管理者( NameNode )。

NameNode實際上就是

管理文件的各種信息 (這種信息專業點我們叫做 MetaData 「元數據」),其中包括:文文件路徑名,每個Block的ID和存放的位置等等。

所以,無論是讀還是寫,HDFS客戶端都會先去找 NameNode ,通過NameNode得知相應的信息,再去找DataNode

  • 如果是寫操作,HDFS切分完文件以後,會詢問NameNode應該將這些切分好的block往哪幾臺DataNode上寫。
  • 如果是讀操作,HDFS拿到文件名,也會去詢問NameNode應該往哪幾臺DataNode上讀數據。
什麼是HDFS?算了,告訴你也不懂

2.1 HDFS備份

作為一個分佈式系統(把大文件切分為多個小文件,存儲到不同的機器上),如果沒有備份的話,只要有其中的一臺機器掛了,那就會導致「數據」是不可用狀態的。

寫到這裡,如果看過我的 KafkaElasticSearch

的文章可能就懂了。其實思想都是一樣的。

Kafka對partition備份,ElasticSearch對分片進行備份,而到HDFS就是對Block進行備份。

儘可能將數據備份到不同的機器上,即便某臺機器掛了,那就可以將備份數據拉出來用。

對Kafka和ElasticSearch不瞭解的同學,可以關注我的 GitHub ,搜索關鍵字即可查詢(我覺得還算寫得比較通俗易懂的)

注:這裡的備份並不需要HDFS客戶端去寫,只要DataNode之間互相傳遞數據就好了。

什麼是HDFS?算了,告訴你也不懂

2.2 NameNode的一些事

從上面我們可以看到,NameNode是需要處理hdfs客戶端請求的。(因為它是存儲元數據的地方,無論讀寫都需要經過它)。

現在問題就來了,NameNode是怎麼存放元數據的呢?

  • 如果NameNode只是把元數據放到內存中,那如果NameNode這臺機器重啟了,那元數據就沒了。
  • 如果NameNode將每次寫入的數據都存儲到硬盤中,那如果 只針對磁盤 查找和修改又會很慢(因為這個是 純IO 的操作)

說到這裡,又想起了Kafka。Kafka也是將partition寫到磁盤裡邊的,但人家是怎麼寫的? 順序IO

NameNode同樣也是做了這個事:修改內存中的元數據,然後把修改的信息 append (追加)到一個名為 editlog 的文件上。

由於append是順序IO,所以效率也不會低。現在我們增刪改查都是走內存,只不過增刪改的時候往磁盤文件 editlog 裡邊追加一條。這樣我們即便重啟了NameNode,還是可以通過 editlog 文件將元數據恢復。

什麼是HDFS?算了,告訴你也不懂

現在也有個問題:如果NameNode一直長期運行的話,那 editlog 文件應該會越來越大(因為所有的修改元數據信息都需要在這追加一條)。重啟的時候需要依賴 editlog 文件來恢復數據,如果文件特別大,那啟動的時候不就特別慢了嗎?

的確是如此的,那HDFS是怎麼做的呢?為了防止 editlog 過大,導致在重啟的時候需要較長的時間恢復數據,所以NameNode會有一個 內存快照 ,叫做 fsimage

說到快照,有沒有想起Redis的RDB!!

這樣一來,重啟的時候只需要加載內存快照 fsimage +部分的 editlog 就可以了。

想法很美好,現實還需要解決一些事:我什麼時候生成一個內存快照 fsimage ?我怎麼知道加載哪一部分的 editlog ?

問題看起來好像複雜,其實我們就只需要一個 定時任務

如果讓我自己做的話,我可能會想:我們加一份配置,設置個時間就OK了

  • 如果 editlog 大到什麼程度或者隔了多長時間,我們就把editlog文件的數據跟內存快照 fsiamge 給合併起來。然後生成一個新的 fsimage ,把 editlog 給清空,覆蓋舊的 fsimage 內存快照
  • 這樣一來,NameNode每次重啟的時候,拿到的都是最新的fsimage文件,editlog裡邊的都是沒合併到fsimage的。根據這兩個文件就可以恢復最新的元數據信息了。

HDFS也是類似上面這樣乾的,只不過它不是在NameNode起個定時的任務跑,而是用了一個新的角色: SecondNameNode

。至於為什麼?可能HDFS覺得 合併所耗費的資源太大 了,不同的工作交由不同的服務器來完成,也符合分佈式的理念。

什麼是HDFS?算了,告訴你也不懂

現在問題還是來了,此時的架構 NameNode是單機 的。SecondNameNode的作用只是給NameNode合併 editlog 和 fsimage 文件,如果NameNode掛了,那client就請求不到了,而所有的請求都需要走NameNode,這導致整個HDFS集群都不可用了。

於是我們需要保證NameNode是高可用的。一般現在我們會通過 Zookeeper 來實現。架構圖如下:

什麼是HDFS?算了,告訴你也不懂

主NameNode和從NameNode需要保持元數據的信息一致(因為如果主NameNode掛了,那從NameNode需要頂上,這時從NameNode需要有主NameNode的信息)。

所以,引入了Shared Edits來實現主從NameNode之間的同步,Shared Edits也叫做 JournalNode 。實際上就是主NameNode如果有更新元數據的信息,它的 editlog 會寫到JournalNode,然後從NameNode會在JournalNode讀取到變化信息,然後同步。從NameNode也實現了上面所說的SecondNameNode功能(合併editlog和fsimage)

什麼是HDFS?算了,告訴你也不懂

稍微總結一下:

  • NameNode需要處理client請求,它是存儲元數據的地方
  • NameNode的元數據操作都在內存中,會把增刪改以 editlog 持續化到硬盤中(因為是順序io,所以不會太慢)
  • 由於 editlog 可能存在過大的問題,導致重新啟動NameNode過慢(因為要依賴 editlog 來恢復數據),引出了 fsimage 內存快照。需要跑一個定時任務來合併 fsimage 和 editlog ,引出了 SecondNameNode
  • 又因為NameNode是單機的,可能存在單機故障的問題。所以我們可以通過Zookeeper來維護主從NameNode,通過JournalNode(Share Edits)來實現主從NameNode元數據的一致性。最終實現NameNode的高可用。

2.3 學點DataNode

從上面我們就知道,我們的數據是存放在DataNode上的(還會備份)。

如果某個DataNode掉線了,那HDFS是怎麼知道的呢?

DataNode啟動的時候會去NameNode上註冊,他倆會維持 心跳 ,如果超過時間閾值沒有收到DataNode的心跳,那HDFS就認為這個DataNode掛了。

還有一個問題就是:我們將Block存到DataNode上,那還是有可能這個DataNode的磁盤 損壞了部分 ,而我們DataNode沒有下線,但我們也不知道損壞了。

一個Block除了存放數據的本身,還會存放一份元數據(包括數據塊的長度,塊數據的校驗和,以及時間戳)。DataNode還是會 定期 向NameNode上報所有當前所有Block的信息,通過 元數據就可校驗當前的Block是不是正常狀態

最後

其實在學習HDFS的時候,你會發現很多的思想跟之前學過的都類似。就比如提到的Kafka、Elasticsearch這些常用的分佈式組件。

如果對Kafka、Elasticsearch、Zookeeper、Redis等不瞭解的同學,可以在我的GitHub或公眾號裡邊找對應的文章哦~我覺得還算寫得通俗易懂的。

改天整合一下這些框架的持久化特點,再寫一篇(因為可以發現,他們的持久化機制都十分類似)


分享到:


相關文章: