天天看點

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

前言

隻有光頭才能變強。
文本已收錄至我的GitHub精選文章,歡迎Star:https://github.com/ZhongFuCheng3y/3y

上一篇已經講解了「大資料入門」的相關基礎概念和知識了,這篇我們來學學HDFS。如果文章有錯誤的地方,不妨在評論區友善指出~

一、HDFS介紹

上篇文章已經講到了,随着資料量越來越大,在一台機器上已經無法存儲所有的資料了,那我們會将這些資料配置設定到不同的機器來進行存儲,但是這就帶來一個問題:不友善管理和維護

是以,我們就希望有一個系統可以将這些分布在不同操作伺服器上的資料進行統一管理,這就有了分布式檔案系統

  • HDFS是分布式檔案系統的其中一種(目前用得最廣泛的一種)

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

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

明确一下:HDFS就是一個分布式檔案系統,一個檔案系統,我們用它來做什麼?存資料呀。

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

二、HDFS學習

從上面我們已經提到了,HDFS作為一個分布式檔案系統,那麼它的資料是儲存在多個系統上的。例如,下面的圖:一個1GB的檔案,會被切分成幾個小的檔案,每個伺服器都會存放一部分。

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

那肯定會有人會問:那會切分多少個小檔案呢?預設以

128MB

的大小來切分,每個

128MB

的檔案,在HDFS叫做塊(block)

顯然,這個128MB大小是可配的。如果設定為太小或者太大都不好。如果切分的檔案太小,那一份資料可能分布到多台的機器上(尋址時間就很慢)。如果切分的檔案太大,那資料傳輸時間的時間就很慢。

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備份

作為一個分布式系統(把大檔案切分為多個小檔案,存儲到不同的機器上),如果沒有備份的話,隻要有其中的一台機器挂了,那就會導緻「資料」是不可用狀态的。

寫到這裡,如果看過我的Kafka和ElasticSearch的文章可能就懂了。其實思想都是一樣的。

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裡邊找對應的文章哦~我覺得還算寫得通俗易懂的。

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

下一篇無意外的話,會寫寫MapReduce,感謝你看到這裡。

參考資料:

  • HDFS漫畫
  • 《從零開始學大資料 -李智慧》