1.背景
HDFS最初是參考谷歌GFS論文原理開發(fā)的一個開源產(chǎn)品,由Lucene開源項目的創(chuàng)始人Doug Cutting開發(fā),現(xiàn)在已經(jīng)成為大數(shù)據(jù)平臺的基石。HDFS借鑒了GFS的技術(shù)架構(gòu),在設(shè)計理念上又與GFS有很大的不同,它致力于提供一個通用的分布式文件系統(tǒng),與GFS作為Google內(nèi)部存儲系統(tǒng)的定位有很大區(qū)別。
HDFS定義了一套文件系統(tǒng)API規(guī)范(http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/filesystem/index.html),確立了HDFS的核心模型,為用戶提供了一個穩(wěn)定的依賴。
HDFS的核心模型:
- 名稱
HDFS文件、目錄的命名規(guī)則,及其邏輯關(guān)系,與Linux普通文件系統(tǒng)看起來幾乎一模一樣。
- 原子性
在HDFS中,創(chuàng)建文件、刪除文件、重命名文件、重命名目錄、創(chuàng)建目錄都是原子操作。遞歸刪除目錄也是原子操作。
- 一致性
HDFS的一致性模型是”復制-更新“語義,我理解就是是強一致模型。
Create、Update、Delete、Delete then create、Rename操作,在操作結(jié)束后,結(jié)果必須對后續(xù)的訪問可見。
- 并發(fā)
HDFS對并發(fā)操作沒有數(shù)據(jù)隔離保證。假如一個Client在訪問文件的同時,另一個Client正在修改文件,那么修改的內(nèi)容可能可見,也可能不可見。
- 操作失敗
所有操作必須最終完成,要么成功,要么失敗。
實現(xiàn)通過重試來保證操作成功,前提是保證一致性語義,并且重試操作對Client透明。
- 超時
HDFS對操作的超時沒有定義。
在HDFS中,阻塞操作超時實際上是可變的,因為站點和客戶機可能會調(diào)優(yōu)重試參數(shù),從而將文件系統(tǒng)故障和故障排除程序轉(zhuǎn)換為操作中的暫停。取而代之的是一種普遍的假設(shè),即FS操作“快但沒有本地FS操作快”,并且數(shù)據(jù)讀寫的延遲隨數(shù)據(jù)量的增加而增加??蛻魴C應(yīng)用程序的這種假設(shè)揭示了一個更基本的假設(shè):文件系統(tǒng)性能接近網(wǎng)絡(luò)延遲和帶寬上線。
對于某些操作的開銷也有一些隱含的假設(shè)。seek()操作非???,幾乎不會造成網(wǎng)絡(luò)延遲。對于條目較少的目錄,目錄列表操作非???。
- vs 對象存儲
HDFS與對象存儲(例如S3)有明顯的不同,
對象存儲是最終一致性模型。也就是說,一個操作的結(jié)果,要經(jīng)過一段時間才能被所有的Client看到,在此之前,Client可能訪問到過期數(shù)據(jù)。
原子性。對象存儲沒有目錄的概念,雖然可以通過基于文件名前綴的操作,來達到類似的效果,比如通過刪除前綴/user的文件,來達到刪除/user目錄的效果,但這不是一個原子操作,而是一個文件一個文件的獨立操作。
持久性。HDFS和傳統(tǒng)文件持久化非常相近,調(diào)用flush,close,文件以流的形式不停得更新到存儲。而對象存儲只有對文件操作結(jié)束后的時刻,才把完整的文件PUT到存儲系統(tǒng)。
權(quán)限。HDFS提供傳統(tǒng)文件系統(tǒng)的用戶、組權(quán)限管理概念,對象存儲通常沒有。
2.架構(gòu)
HDFS架構(gòu)和GFS非常相近,可以參考上一篇筆記《GFS架構(gòu)剖析》,這里只說一下二者的區(qū)別。
2.1 Moving Computation is Cheaper than Moving Data
這是HDFS的一個設(shè)計預期和目標,也是Hadoop大數(shù)據(jù)處理的精髓所在。
2.2 The File System Namespace
HDFS目標是做一個通用文件系統(tǒng),支持傳統(tǒng)的文件、目錄概念。在這方面,GFS更像一個對象存儲,它不支持文件系統(tǒng)模型。
2.3 BlockId
根據(jù)[1],早期block id是一個64位數(shù)隨機數(shù)。當時實現(xiàn)比較簡單,并沒有判重,所以如果兩個block碰巧得到同樣的block id,系統(tǒng)會誤認為是多余的備份block,而將其中一個刪除。這樣這個block很有可能會出錯,包含它的文件則損壞。解決的辦法有兩個,一是記錄好所有使用過的block id,以實現(xiàn)判重功能;二是以一種不會重復的方式生成block id,比如順序生成。順序生成的缺點有三個,一是現(xiàn)有的系統(tǒng)遷移困難,所有的block都要重新命名;二是用完了64位數(shù)后仍然有麻煩;三是要記錄好最高的block id。
判重并不是最優(yōu)的方法,因為它需要額外的工作,而且隨著文件系統(tǒng)變得龐大將變重。假設(shè)用一個Hash實現(xiàn)判重,一個1PB的文件系統(tǒng),假設(shè)1個block大小64MB,則包含有16M個block id,每個id為8個byte,則需要一個128MB的Hash表,這對于一個本身就很復雜的NameNode是個不小的壓力。[2]中提出了一種綜合的方法,給一個文件的所有block指定一個相同的range id(5個byte)作為它們block id的高位,然后按順序每個block生成剩余的3個byte。較之前的單純判重,好處在于減小了判重的數(shù)量;同時又方便管理同一個文件的block,因為它們的block id是連續(xù)的。[2]也指出這種方法的問題,當一個文件被刪除時,此range id要從系統(tǒng)中抹去,如果此時某個包含此文件某block的數(shù)據(jù)結(jié)點掉線了,在它重新上線之后,它又帶回這個已經(jīng)無效的range id。所以需要timestamps,即creation time of the file,當兩個文件碰巧有相同的range id時,根據(jù)timestamps來判定誰是最新的文件,舊的文件將被刪除。[2]中能看到Doug Cutting和Sameer Paranjpye的一些其它討論,比如range-id也采用順序生成(又回到隨機VS順序的問題上)。
[1] potential conflict in block id's, leading to data corruption
https://issues.apache.org/jira/browse/HADOOP-146
[2] dfs should allocate a random blockid range to a file, then assign ids sequentially to blocks in the file
https://issues.apache.org/jira/browse/HADOOP-158
[3] Sequential generation of block ids
https://issues.apache.org/jira/browse/HDFS-898
2.4 數(shù)據(jù)校驗
硬盤故障、網(wǎng)絡(luò)錯誤或軟件漏洞,都可能造成數(shù)據(jù)損壞。客戶端創(chuàng)建文件時,會針對文件的每一個Block計算校驗碼,并把校驗碼存儲在相同命名空間一個單獨的因此文件中。當客戶端讀數(shù)據(jù)時,會使用這些校驗碼進行數(shù)據(jù)驗證。如果校驗失敗,客戶端會從其他副本重新拉取文件。
這一點上HDFS與GFS差異明顯。GFS數(shù)據(jù)校驗是在chunkserver上做的,并且是對每一個64K的塊計算一個校驗碼,應(yīng)用程序也需要構(gòu)建自己的記錄校驗碼,因為GFS文件可能中可能存在填充數(shù)據(jù)、重復數(shù)據(jù)。而HDFS是強一致模型,各副本在字節(jié)上完全一致,所以客戶端可以直接使用每一個Block的校驗碼進行數(shù)據(jù)校驗。
2.5 元數(shù)據(jù)備份與恢復
2.5.1 Secondary NameNode
Secondary NameNode不是NameNode的備份。它的作用是:定期合并fsImage和editsLog,并推送給NameNode,輔助恢復NameNode(editsLog越大NameNode恢復越慢)。
Secondary NameNode的作用現(xiàn)在可以被CheckpointNode和BackupNode替換掉。
Secondary NameNode定期合并流程,如下圖所示。
2.5.2 Checkpoint Node
CheckpointNode和SecondaryNameNode的作用以及配置完全相同。
2.5.3 Backup Node
Backup Node在內(nèi)存中維護了一份從Namenode同步過來的fsimage,同時它還從namenode接收edits文件的日志流,并把它們持久化硬盤,Backup Node把收到的這些edits文件和內(nèi)存中的fsimage文件進行合并,創(chuàng)建一份元數(shù)據(jù)備份。Backup Node高效的秘密就在這兒,它不需要從Namenode下載fsimage和edit,把內(nèi)存中的元數(shù)據(jù)持久化到磁盤然后進行合并即可。
配置了BackupNode以后,NameNode自身不再需要持久化存儲,而是把這個職責完全委托給BackupNode。
目前,hadoop集群只支持一個Backup Node,如果Backup Node出了問題,Hadoop元數(shù)據(jù)的備份機制也就失效了,所以hadoop計劃在未來能支持多個Backup Node。
2.5.4 Recovery Mode
當所有的元數(shù)據(jù)備份都失效時,可以啟動Recovery模式,來恢復大部分數(shù)據(jù)。
2.6 NameNode HA
NameNode的HA,指的是在一個集群中存在兩個NameNode,分別運行在獨立的物理節(jié)點上。在任何時間點, 只有一個NameNodes是處于Active狀態(tài),另一種是在Standby狀態(tài)。
Active NameNode負責所有的客戶端的操作,而Standby NameNode用來同步Active NameNode的狀態(tài)信息,以提供快速的故障恢復能力。
為了保證Active NameNode與Standby NameNode節(jié)點狀態(tài)同步,即元數(shù)據(jù)保持一致。除了DataNode需要向兩個NN發(fā)送block位置信息外,還構(gòu)建了一組獨立的守護進程”JournalNodes” ,用來同步FsEdits信息。當Active NameNode執(zhí)行任何有關(guān)命名空間的修改,它需要持久化到一半以上的JournalNodes上。而Standby NameNode負責觀察JNs的變化,讀取從Active NameNode發(fā)送過來的FsEdits信息,并更新其內(nèi)部的命名空間。
一旦Active NameNode遇到錯誤, Standby NameNode需要保證從JNs中讀出了全部的FsEdits, 然后切換成Active狀態(tài)。
在這個圖里,我們可以看出HA的大致架構(gòu),其設(shè)計上的考慮包括:
- 利用共享存儲來在兩個NN間同步edits信息。
共享存儲有兩個方案,一是通過NFS,在中高端的存儲設(shè)備內(nèi)部都有各種RAID以及冗余硬件包括電源以及網(wǎng)卡等,比服務(wù)器的可靠性還是略有提高。二是通過QJM集群,QJM集群有一個特性,數(shù)據(jù)寫入只有被集群的大多數(shù)節(jié)點接受,才算寫入成功,這也就保證任何時刻,只有一個NameNode可以寫入數(shù)據(jù)。
- DataNode同時向兩個NameNode匯報塊信息。
這是讓Standby NameNode保持集群最新狀態(tài)的必需步驟。
- 用于監(jiān)視和控制NN進程的FailoverController進程
顯然,我們不能在NameNode進程內(nèi)進行心跳等信息同步。最簡單的原因,一次FullGC就可以讓NameNode掛起十幾分鐘。所以,必須要有一個獨立的短小精悍的watchdog來專門負責監(jiān)控。這也是一個松耦合的設(shè)計,便于擴展或更改,目前版本里是用ZooKeeper(以下簡稱ZK)來做同步鎖,但用戶可以方便的把這個ZooKeeper FailoverController(以下簡稱ZKFC)替換為其他的HA方案或leader選舉方案。
- 隔離(Fencing),防止腦裂,就是保證在任何時候只有一個主NameNode,包括三個方面:
共享存儲fencing,確保只有一個NameNode可以寫入edits。
客戶端fencing,確保只有一個NameNode可以響應(yīng)客戶端的請求。
DataNode fencing,確保只有一個NameNode可以向DateNode下發(fā)命令,譬如刪除,復制等等。
2.7 Multiple NameNodes/Namespaces
HDFS提供了一種水平擴展方案,即通過NameNode集群+共享DateNode的方式,支持多個獨立的命名空間。
DateNode向集群的所有NameNode注冊,周期性發(fā)送心跳,發(fā)送BlockReport。NameNode之間彼此不通信。
每一個NameNode維護自己的BlockPools,BlockPools在DataNode上被單獨管理。因此,NameNode節(jié)點之間不需要任何同步,可以單獨生成Block IDs。當一個NameNode發(fā)生故障時,不影響DateNode向其他的NameNode正常提供服務(wù)。
命名空間和它的BlockPool一起構(gòu)成一個“卷”,它是一個獨立管理的單位,當一個"卷"被刪除時,BlockPool對應(yīng)的Block也會被DateNode節(jié)點刪除。在集群升級期間,每個命名空間卷作為一個單元進行升級。
這種方案帶來的好處:
- 命名空間可擴展性:在使用小文件的場景中,可以從擴展多個命名空間獲益。
- 性能:使性能不再局限于一個NameNode節(jié)點。
- 隔離:通過命名空間避免不同的應(yīng)用,避免互相影響。
為了讓多個命名空間對Client看起來還像是一個集群,可以使用ViewFs。這就像是Linux文件系統(tǒng)的掛載表,每個文件系統(tǒng)掛載在一個目錄上,使用起來,看到的是一個命名空間,不必關(guān)心具體是由幾個文件系統(tǒng)構(gòu)成的。
為了給Client提供一個統(tǒng)一視圖,HDFS提供了一個Router方案,即通過Router代理Client對NameNode的請求,使多集群對Client透明。
最簡單的配置是在每個NameNode機器上部署Router。當ClientS訪問文件系統(tǒng)中的文件時,路由器檢查StateStore找出哪個子集群包含該文件, 然后代理請求到相應(yīng)的NameNode。
2.8 配額
HDFS支持對一個目錄下的子目錄和文件數(shù)進行限額,對一個目錄的存儲空間限額,對一個目錄在不同存儲介質(zhì)上的存儲空間(DISK/SSD/ARCHIVE)。限額數(shù)據(jù)在NameNode被持久化保存。
2.9 訪問接口
HDFS支持眾多訪問接口,包括:
- Shell
- 標準Java API
- HFTP
- C API libhdfs
- RestApi
- NFS GateWay
2.10 集中的緩存管理
HDFS提供了一種集中式緩存管理機制,允許用戶指定HDFS緩存的路徑。NameNode與存儲相應(yīng)下文件的DateNode進行通信,指示它們將塊緩存到堆外緩存中。
2.10.1 主要解決了哪些問題
用戶可以根據(jù)自己的邏輯指定一些經(jīng)常被使用的數(shù)據(jù)或者高優(yōu)先級任務(wù)對應(yīng)的數(shù)據(jù)常駐內(nèi)存而不被淘汰到磁盤。例如在Hive或Impala構(gòu)建的數(shù)據(jù)倉庫應(yīng)用中fact表會頻繁地與其他表做JOIN,顯然應(yīng)該讓fact常駐內(nèi)存,這樣DataNode在內(nèi)存使用緊張的時候也不會把這些數(shù)據(jù)淘汰出去,同時也實現(xiàn)了對于 mixed workloads的SLA。
centralized cache是由NameNode統(tǒng)一管理的,那么HDFS client(例如MapReduce、Impala)就可以根據(jù)block被cache的分布情況去調(diào)度任務(wù),做到memory-locality。
HDFS原來單純靠DataNode的OS buffer cache,這樣不但沒有把block被cache的分布情況對外暴露給上層應(yīng)用優(yōu)化任務(wù)調(diào)度,也有可能會造成cache浪費。例如一個block的三個replica分別存儲在三個DataNote 上,有可能這個block同時被這三臺DataNode的OS buffer cache,那么從HDFS的全局看就有同一個block在cache中存了三份,造成了資源浪費。
加快HDFS client讀速度。過去NameNode處理讀請求時只根據(jù)拓撲遠近決定去哪個DataNode讀,現(xiàn)在還要加入speed的因素。當HDFS client和要讀取的block被cache在同一臺DataNode的時候,可以通過zero-copy read直接從內(nèi)存讀,略過磁盤I/O、checksum校驗等環(huán)節(jié)。
2.10.2 架構(gòu)和原理
用戶可以通過hdfs cacheadmin命令行或者HDFS API顯式指定把HDFS上的某個文件或者目錄放到HDFS centralized cache中。這個centralized cache由分布在每個DataNode節(jié)點的off-heap內(nèi)存組成,同時被NameNode統(tǒng)一管理。每個DataNode節(jié)點使用mmap/mlock把存儲在磁盤文件中的HDFS block映射并鎖定到off-heap內(nèi)存中。
Client讀取文件時向NameNode發(fā)送getBlockLocations RPC請求。NameNode會返回一個LocatedBlock列表給Client,這個LocatedBlock對象里有這個block的replica所在的DataNode和cache了這個block的DataNode??梢岳斫鉃榘驯籧ache到內(nèi)存中的replica當做三副本外的一個高速的replica。
2.10.3 對應(yīng)用的影響
對于HDFS上的某個目錄已經(jīng)被addDirective緩存起來之后,如果這個目錄里新加入了文件,那么新加入的文件也會被自動緩存。這一點對于Hive/Impala式的應(yīng)用非常有用。
HBase in-memory table:可以直接把某個HBase表的HFile放到centralized cache中,這會顯著提高HBase的讀性能,降低讀請求延遲。
和Spark RDD的區(qū)別:多個RDD的之間的讀寫操作可能完全在內(nèi)存中完成,出錯就重算。HDFS centralized cache中被cache的block一定是先寫到磁盤上的,然后才能顯式被cache到內(nèi)存。也就是說只能cache讀,不能cache寫。
目前的centralized cache不是DFSClient讀了誰就會把誰cache,而是需要DFSClient顯式指定要cache誰,cache多長時間,淘汰誰。目前也沒有類似LRU的置換策略,如果內(nèi)存不夠用的時候需要client顯式去淘汰對應(yīng)的directive到磁盤。
現(xiàn)在還沒有跟YARN整合,需要用戶自己調(diào)整留給DataNode用于cache的內(nèi)存和NodeManager的內(nèi)存使用。
2.11 HDFS讀寫流程
2.11.1 HDFS中的block、packet、chunk
要把讀寫過程細節(jié)搞明白前,必須知道block、packet與chunk。
- block
這個大家應(yīng)該知道,文件上傳前需要分塊,這個塊就是block,一般為128MB,當然你可以去改,不過不推薦。因為塊太?。簩ぶ窌r間占比過高。塊太大:Map任務(wù)數(shù)太少,作業(yè)執(zhí)行速度變慢。它是最大的一個單位。
- packet
packet是第二大的單位,它是client端向DataNode,或DataNode的PipLine之間傳數(shù)據(jù)的基本單位,默認64KB。
- chunk
chunk是最小的單位,它是client向DataNode,或DataNode的PipLine之間進行數(shù)據(jù)校驗的基本單位,默認512Byte,因為用作校驗,故每個chunk需要帶有4Byte的校驗位。所以實際每個chunk寫入packet的大小為516Byte。由此可見真實數(shù)據(jù)與校驗值數(shù)據(jù)的比值約為128 : 1。(即64*1024 / 512)
例如,在client端向DataNode傳數(shù)據(jù)的時候,HDFSOutputStream會有一個chunk buff,寫滿一個chunk后,會計算校驗和并寫入當前的chunk(追加操作如何計算chunk的校驗碼?)。之后再把帶有校驗和的chunk寫入packet,當一個packet寫滿后,packet會進入dataQueue隊列,其他的DataNode就是從這個dataQueue獲取client端上傳的數(shù)據(jù)并存儲的。同時一個DataNode成功存儲一個packet后之后會返回一個ack packet,放入ack Queue中。
2.11.2 讀流程
HDFS的讀主要有三種: 網(wǎng)絡(luò)I/O讀 -> short circuit read -> zero-copy read。網(wǎng)絡(luò)I/O讀就是傳統(tǒng)的HDFS讀,通過DFSClient和Block所在的DataNode建立網(wǎng)絡(luò)連接傳輸數(shù)據(jù)。
當DFSClient和它要讀取的block在同一臺DataNode時,DFSClient可以跨過網(wǎng)絡(luò)I/O直接從本地磁盤讀取數(shù)據(jù),這種讀取數(shù)據(jù)的方式叫short circuit read。
目前HDFS實現(xiàn)的short circuit read是通過共享內(nèi)存獲取要讀的block在DataNode磁盤上文件的file descriptor(因為這樣比傳遞文件目錄更安全),然后直接用對應(yīng)的file descriptor建立起本地磁盤輸入流,所以目前的short circuit read也是一種zero-copy read。這需要在DataNode和Client做配置。
增加了Centralized cache的HDFS的讀接口并沒有改變。DFSClient通過RPC獲取LocatedBlock時里面多了個成員表示哪個DataNode把這個block cache到內(nèi)存里面了。如果DFSClient和該block被cache的DataNode在一起,就可以通過zero-copy read大大提升讀效率。而且即使在讀取的過程中該block被uncache了,那么這個讀就被退化成了本地磁盤讀,一樣能夠獲取數(shù)據(jù)。
2.11.3 寫流程
寫詳細步驟:
1.客戶端向NameNode發(fā)出寫文件請求。
2.檢查是否已存在文件、檢查權(quán)限。若通過檢查,直接先將操作寫入EditLog,并返回輸出流對象。
注:WAL,write ahead log,先寫Log,再寫內(nèi)存,因為EditLog記錄的是最新的HDFS客戶端執(zhí)行所有的寫操作。如果后續(xù)真實寫操作失敗了,由于在真實寫操作之前,操作就被寫入EditLog中了,故EditLog中仍會有記錄,我們不用擔心后續(xù)client讀不到相應(yīng)的數(shù)據(jù)塊,因為在第5步中DataNode收到塊后會有一返回確認信息,若沒寫成功,發(fā)送端沒收到確認信息,會一直重試,直到成功。
3.client端按128MB的塊切分文件。
4.client將NameNode返回的分配的可寫的DataNode列表和Data數(shù)據(jù)一同發(fā)送給最近的第一個DataNode節(jié)點,此后client端和NameNode分配的多個DataNode構(gòu)成pipeline管道,client端向輸出流對象中寫數(shù)據(jù)。client每向第一個DataNode寫入一個packet,這個packet便會直接在pipeline里傳給第二個、第三個…DataNode。
注:并不是寫好一個塊或一整個文件后才向后分發(fā)
5.每個DataNode寫完一個塊后,會返回確認信息。
注:并不是每寫完一個packet后就返回確認信息,個人覺得因為packet中的每個chunk都攜帶校驗信息,沒必要每寫一個就匯報一下,這樣效率太慢。正確的做法是寫完一個block塊后,對校驗信息進行匯總分析,就能得出是否有塊寫錯的情況發(fā)生。
6.寫完數(shù)據(jù),關(guān)閉輸輸出流。
7.發(fā)送完成信號給NameNode。
注:發(fā)送完成信號的時機取決于集群是強一致性還是最終一致性,強一致性則需要所有DataNode寫完后才向NameNode匯報。最終一致性則其中任意一個DataNode寫完后就能單獨向NameNode匯報,HDFS一般情況下都是強調(diào)強一致性。
在寫數(shù)據(jù)的過程中,如果Pipeline數(shù)據(jù)流管道中的一個DataNode節(jié)點寫失敗了會發(fā)生什問題、需要做哪些內(nèi)部處理呢?如果這種情況發(fā)生,那么就會執(zhí)行一些操作:
首先,Pipeline數(shù)據(jù)流管道會被關(guān)閉,ack queue中的packets會被添加到data queue的前面以確保不會發(fā)生packets數(shù)據(jù)包的丟失;
接著,在正常的DataNode節(jié)點上的以保存好的block的ID版本會升級——這樣發(fā)生故障的DataNode節(jié)點上的block數(shù)據(jù)會在節(jié)點恢復正常后被刪除,失效節(jié)點也會被從Pipeline中刪除;
最后,剩下的數(shù)據(jù)會被寫入到Pipeline數(shù)據(jù)流管道中的其他兩個節(jié)點中。
如果Pipeline中的多個節(jié)點在寫數(shù)據(jù)是發(fā)生失敗,那么只要寫成功的block的數(shù)量達到dfs.replication.min(默認為1),那么就任務(wù)是寫成功的,然后NameNode后通過一步的方式將block復制到其他節(jié)點,最后事數(shù)據(jù)副本達到dfs.replication參數(shù)配置的個數(shù)。
在一個繁忙的HDFS集群當中,可能會發(fā)生DateNode寫失敗的情況。此時,NameNode就會把這個DateNode實例排除掉,去尋找新的可用DateNode。假如集群的可用DateNode數(shù)較少,找不到新的可用DateNode,文件無法恢復到要求的副本數(shù),就會導致文件無法再寫入。
解決辦法有兩個:
- 增加集群的機器數(shù)量。
- 修改配置,讓寫入的行為發(fā)生改變。dfs.client.block.write.replace-datanode-on-failure.enable配置默認是true,表示如果在寫入的pipeline有datanode失敗的時候是否要切換到新的機器。但是如果集群比較小的話,有兩臺機器失敗的話,就沒有其他機器可以切換了,所以把該配置設(shè)置成false后就能解決問題。
2.11.3 讀寫流程如何保證一致性
通過校驗和。因為每個chunk中都有一個校驗位,一個個chunk構(gòu)成packet,一個個packet最終形成block,故可在block上求校驗和。HDFS的client端即實現(xiàn)了對HDFS文件內(nèi)容的校驗和(checksum)檢查。
當客戶端創(chuàng)建一個新的HDFS文件時候,分塊后會計算這個文件每個數(shù)據(jù)塊的校驗和,此校驗和會以一個隱藏文件形式保存在同一個HDFS命名空間下。當client端從HDFS中讀取文件內(nèi)容后,它會檢查分塊時候計算出的校驗和(隱藏文件里)和讀取到的文件塊中校驗和是否匹配,如果不匹配,客戶端可以選擇從其他 Datanode 獲取該數(shù)據(jù)塊的副本。
HDFS中文件塊目錄結(jié)構(gòu)具體格式如下:
${dfs.datanode.data.dir}/
├── current
│ ├── BP-526805057-127.0.0.1-1411980876842
│ │ └── current
│ │ ├── VERSION
│ │ ├── finalized
│ │ │ ├── blk_1073741825
│ │ │ ├── blk_1073741825_1001.meta
│ │ │ ├── blk_1073741826
│ │ │ └── blk_1073741826_1002.meta
│ │ └── rbw
│ └── VERSION
└── in_use.lock
in_use.lock表示DataNode正在對文件夾進行操作
rbw是“replica being written”的意思,該目錄用于存儲用戶當前正在寫入的數(shù)據(jù)。
Block元數(shù)據(jù)文件(*.meta)由一個包含版本、類型信息的頭文件和一系列校驗值組成。校驗和也正是存在其中。
2.11.4 透明、端到端數(shù)據(jù)加密
2.11.5 多宿主網(wǎng)絡(luò)
2.11.6 歸檔存儲,SSD,內(nèi)存
HDFS為分離冷熱數(shù)據(jù)提供了支持,通過storagepolicies命令行工具可以指定一個目錄(遞歸)或文件的存儲策略。當然,必須首先在DateNode啟用存儲策略,并配置不同的存儲介質(zhì)。
- 存儲類型:ARCHIVE, DISK, SSD and RAM_DISK
HDFS支持異構(gòu)存儲,DateNode支持多個存儲,每個存儲對應(yīng)一種存儲介質(zhì)。
ARCHIVE:我理解這泛指高密度歸檔存儲設(shè)備。
RAM_DISK:要求Client位于DataNode節(jié)點上,因為跨網(wǎng)絡(luò)時延足以抵消內(nèi)存寫入帶來的好處。
- 存儲策略:Hot, Warm, Cold, All_SSD, One_SSD and Lazy_Persist
HDFS定義了集中存儲策略,
- Hot - 熱數(shù)據(jù),有存儲和計算的雙重用途。所有的副本都存儲在DISK。
- Cold - 冷數(shù)據(jù),數(shù)據(jù)已經(jīng)不再使用,僅僅是歸檔保存。所有副本存儲在ARCHIVE。
- Warm - 溫數(shù)據(jù)。部分副本存儲在DISK,其他副本存儲在ARCHIVE。
- All_SSD - 所有副本存儲在SSD。
- One_SSD - 一個副本存儲在SSD,其他副本存在在DISK。
- Lazy_Persist - 用于在內(nèi)存中寫入具有單個副本的塊。副本首先在RAM_DISK中寫入,然后在DISK中惰性持久化。