3.6 數(shù)據(jù)流
3.6.1 剖析文件讀取
客戶端讀取HDFS數(shù)據(jù).png
- 1、客戶端調(diào)用
DistributedFileSystem.open
方法以打開希望讀取的文件,DistributedFileSystem初始化的時(shí)候(參見:java.util.ServiceLoader加載服務(wù)實(shí)現(xiàn)類)創(chuàng)建了一個(gè)DFSClient
實(shí)例,DFSClient
通過RPC向namenode發(fā)送請求獲取文件塊位置,對于每個(gè)數(shù)據(jù)塊,namenode返回該塊所有復(fù)本datanode地址,這些datanode根據(jù)它們與客戶端的距離排序,若客戶端本身就是一個(gè)datanode,那么該客戶端會(huì)從本地讀取數(shù)據(jù)。- 2、
DistributedFileSystem.open
返回一個(gè)FSDataInputStream
對象,該對象封裝了一個(gè)DFSInputStream
,DFSInputStream
封裝了DFSClient、Datanode、LocatedBlock
;- 3、
FSDataInputStream.read
,反復(fù)調(diào)用,達(dá)到塊末端,DFSInputStream
關(guān)閉與datanode連接,尋找下一個(gè)塊的最佳datanode。若DFSInputStream
與datanode通信時(shí)發(fā)生錯(cuò)誤,會(huì)嘗試從鄰近datanode讀取數(shù)據(jù)。
可以將namenode理解為服務(wù)發(fā)現(xiàn)組件,datanode為真正服務(wù)響應(yīng)組件。
- 帶寬很稀缺,將兩節(jié)點(diǎn)間帶寬作為距離的衡量標(biāo)準(zhǔn)。
如下場景,可用帶寬依次遞減:
distance(/d1/r1/n1, /d1/r1/n1) = 0(同一節(jié)點(diǎn)上進(jìn)程)
distance(/d1/r1/n1, /d1/r1/n2) = 2(同機(jī)架不同節(jié)點(diǎn))
distance(/d1/r1/n1, /d1/r2/n3) = 4(同數(shù)據(jù)中心不同機(jī)架)
distance(/d1/r1/n1, /d2/r3/n4) = 6(不同數(shù)據(jù)中心)
3.6.2 剖析文件寫入
HDFS文件寫入.png
- 1、
DistributedFileSystem.create
創(chuàng)建文件,DistributedFileSystem
向namenode發(fā)送文件創(chuàng)建RPC請求,namenode檢查文件是否存在及用戶是否有創(chuàng)建文件權(quán)限,若不通過,拋出IO異常- 2、
DistributedFileSystem
返回一個(gè)FSDataOutputStream
,其封裝了一個(gè)DFSOutputStream
,該對象負(fù)責(zé)datanode與namenode間通信- 3、客戶端寫入數(shù)據(jù)時(shí),
DFSOutputStream
將它分成一個(gè)個(gè)數(shù)據(jù)包,并寫入內(nèi)部隊(duì)列(數(shù)據(jù)隊(duì)列data queue),DataStreamer
處理數(shù)據(jù)隊(duì)列,先挑選一組適合存儲數(shù)據(jù)復(fù)本的datanode,并據(jù)此要求namenode分配新的數(shù)據(jù)塊,這組datanode構(gòu)成一個(gè)管線,DataStreamer
將數(shù)據(jù)包流式傳輸?shù)降谝粋€(gè)datanode,該datanode存儲數(shù)據(jù)包并將它發(fā)送到第二個(gè)datanode,同樣第二個(gè)往第三個(gè)datanode傳輸數(shù)據(jù)。- 4、
DFSOutputStream
維護(hù)一個(gè)內(nèi)部數(shù)據(jù)包隊(duì)列(確認(rèn)隊(duì)列ack queue),管道中所有datanode發(fā)送ack消息后,數(shù)據(jù)包才從隊(duì)列移除。
復(fù)本存放
- 1、運(yùn)行客戶端的節(jié)點(diǎn)存放第一個(gè)復(fù)本,若客戶端運(yùn)行于集群之外,則隨機(jī)選擇一個(gè)節(jié)點(diǎn),系統(tǒng)會(huì)盡量避免選擇磁盤太滿或太忙節(jié)點(diǎn);
- 2、第2個(gè)復(fù)本存放于不同機(jī)架隨機(jī)節(jié)點(diǎn)(離架)
- 3、第3個(gè)復(fù)本與第2個(gè)復(fù)本同一個(gè)機(jī)架,不同節(jié)點(diǎn)
- 4、其他節(jié)點(diǎn)隨機(jī)存放,盡量不在同一機(jī)架存放太多復(fù)本
3.6.3 一致模型(coherency model)
- 1、新建文件,立即可見
- 2、寫入文件內(nèi)容(即使已刷新并存儲,
out.flush()
),不保證立即可見,當(dāng)寫入的數(shù)據(jù)超過一個(gè)塊,第一個(gè)塊對新reader可見,正在寫入的塊對其他reader不可見。
兩種強(qiáng)刷緩存至所有datanode手段
FSDataInputStream.hflush()
后,FSDataInputStream.close()
隱含執(zhí)行了hflush()
方法,HDFS保證文件中到目前為止寫入的數(shù)據(jù)均到達(dá)所有datanode寫入管道并對所有reader可見,不保證數(shù)據(jù)寫入磁盤,可能丟失;FSDataInputStream.hsync()
后,刷新到磁盤。
調(diào)用hflush
存在額外性能開銷,hsync
性能開銷更大,需要在數(shù)據(jù)魯棒性和性能之間取得平衡。