客戶端通過呼叫filesystem物件的open()方法來開啟希望讀取的檔案,對於hdfs來說,這個物件是distributedfilesystem
的乙個例項,distributedfilesystem
通過使用遠端過程呼叫(rpc)來呼叫namenode
,以確定檔案起始塊的位置(步驟2),對於每乙個塊,namenode
返回存有該塊副本的datanode
位址,此外,這些datanode
根據他們與客戶端的距離來排序,如果客戶端本身就是乙個datanode
,那麼該客戶端將會從儲存有相應資料塊副本的本地datanode
讀取資料
distributedfilesystem
類返回乙個fsdatainputstream
物件(乙個支援檔案定位的輸入流)給客戶端以便讀取資料,fsdatainputstream
類轉而封裝dfsinputstream
物件,該物件管理著namenode
和datanode
的i/o
接著,客戶端對這個輸入流呼叫read()
方法(步驟3),儲存著檔案起始幾個塊的datanode
位址的dfsinputstream
隨即連線距離最近的檔案中第乙個塊所在的datanode
。通過對資料流反覆呼叫read()
方法,可以將資料從datanode
傳輸到客戶端(步驟4),到達塊的末端時,dfsinputstream
關閉與該datanode
的連線,然後尋找下乙個塊的最佳datanode
(步驟5)。
客戶端從流中讀取資料時,塊是按照開啟dfsinputstream
與datanode
新建連線的順序讀取的,他也會根據需要詢問namenode
來檢索下一批資料塊的datanode
的位置,一旦客戶端完成讀取,就對fsdatainputstream
呼叫close()
方法(步驟6)
在讀取資料的時候,如果dfsinputstream
在與datanode
通訊時遇到錯誤,會嘗試從這個塊的最鄰近datanode
讀取資料,它也記住那個故障datanode
,以保證以後不會反覆讀取該節點上後續的塊。dfsinputstream
也會通過校驗和確認從datanode
發來的資料是否完整。如果發現有損壞的塊,dfsinputstream
會試圖從其他datanode
讀取副本,也會將損壞的塊通知給namenode
這個設計的乙個重點是,客戶端可以直接連線到namenode
檢索資料,且namenode
告知客戶端每個塊所在的最佳datanode
。由於資料流分散在集群中的所有datanode
,所以這種設計能使hdfs擴充套件到大量的併發客戶端。同時,namenode
只需要響應塊位置的請求(這些資訊儲存在記憶體中,因為非常高效),無需響應資料請求,否則隨著客戶端數量的增長,namenode
會很快成為瓶頸
客戶端通過對distributedfilesystem
物件呼叫create()
方法來新建檔案(步驟1),distributedfilesystem
對namenode
建立乙個rpc呼叫,在檔案系統的命名空間中新建乙個檔案,此時該檔案中還沒有響應的資料塊(步驟2),namenode
執行各種不同的檢查以確保這個檔案不存在以及客戶端有新建該檔案的許可權。如果這些檢查均通過,namenode
就會為建立新檔案記錄一條記錄;否則,檔案建立失敗並向客戶端丟擲乙個異常ioexception
。distributedfilesystem
向客戶端返回乙個fsdataoutputstream
物件,由此客戶端可以開始寫入資料,就像讀取事件一樣,fsdataoutputstream
封裝乙個dfsoutputstream
物件,該物件負責處理datanode
和namenode
之間的通訊。
在客戶端寫入資料時(步驟3),dfsoutputstream
將它分成乙個個的資料報,並寫入內部佇列,稱為「資料佇列」(data queue),datastreamer處理資料佇列,它的責任是挑選出適合儲存資料副本的一組datanode
,並據此來要求namenode
分配新的資料塊。這一組datanode
構成乙個管線-----我們假設副本數為3,所以管線中有三個節點。datastreamer
將資料報流式傳輸到管線中的第乙個datanode
,該datanode
儲存資料報並將它傳送到管線中的第二個datanode
,以此類推。
dfsoutputstream
也維護著乙個內部資料報佇列來等待datanode
的收到確認回執,稱為「確認佇列」(ack queue),收到管道中所有datanode
確認訊息後,該資料報才會從確認佇列中刪除(步驟5)
如果任何datanode
在資料寫入時發生故障,則執行以下操作,首先關閉管線,確認把佇列中的所有資料報都新增回資料佇列的最前端,以確保故障節點下游的datanode
不會漏掉任何乙個包。為儲存在另一正常datanode
的當前資料塊指定乙個新的標識,並將該標識傳遞給namenode
,以便故障datanode
在恢復後可以刪除儲存的部分資料塊,從管線中刪除故障datanode
,基於兩個正常datanode
構建一條新管線,餘下的資料塊寫入管線中正常的datanode。namenode
注意到塊副本量不足時,會在另乙個節點上建立乙個新的副本,後續的資料塊繼續正常接受處理。
在乙個塊被寫入期間可能會有多個datanode
同時發生故障,但非常少見,只要寫入了dfs.namenode.replication.min
的副本數,寫操作就會成功,並且這個塊可以在集群中非同步複製,直到達到其目標副本數。
客戶端完成資料的寫入後,對資料流呼叫close()
方法,該操作將剩餘的所有資料報寫入datanode
管線,並在聯絡到namenode
告知其檔案寫入完成之前,等待確認(步驟7),namenode
已經知道檔案有哪些塊組成(因為datastreamer
請求分配資料塊),所以他在返回成功前只需要等待資料塊進行最小量的複製
參考《hadoop權威指南》
檔案讀取和寫入
open 返回乙個檔案物件,open filename,mode f open workfile w 第乙個引數是包含檔名的字串,第二個引數可以是包含一些字元的字串 r 僅讀取檔案,w 僅寫入檔案,a 開啟檔案以進行新增的模式 r 開啟檔案進行讀取和寫入,模式引數是可選的。r 如果省略,將被假定。b...
檔案寫入和讀取
最近在提高自己程式設計能力,拿一些現實的小指令碼練下。該指令碼為python語言,主要涉及模組os。功能 將控制台輸入文字逐行儲存,和讀取。輸入逐行儲存 import os filename input please enter file name file open filename,w whil...
讀取和寫入plist檔案
plist檔案是標準的xml檔案,在cocoa中可以很簡單地使用。這裡介紹一下使用方法 以下 在mac和iphone中均適用。寫入plist檔案 nsmutabledictionary dict nsmutabledictionary alloc initwithcontentsoffile sam...