客戶端與HDFS文件讀取
創建HDFS文件系統實例
FileSystem fs = FileSystem.get(new URI("hdfs://ns1"), new Configuration(),"root");
客戶端通過調用FileSystem對象fs的Open()方法打開要讀取的文件,DistributedFileSystem通過使用RPC來調用NameNode,以確定文件起始塊的位置。
對於文件的每一個塊,NameNode返回存有該塊副本的DataNode地址。這些DataNode根據它們與客戶端的距離來排序(根據集群中的網絡拓撲)。如
果該客戶端本身就是一個DataNode(例如在一個MapReduce任務中)並保存有相應數據塊的一個副本時,該節點就會從本地DataNode讀取數據。然后
DistributedFileSystem返回一個FSDataInputStream對象(支持文件定位的輸入流)給客戶端讀取數據。FSDataInputStream類轉而封裝DFSInputStream
對象,該對象管理着DataNode和NameNode的I/O。
FSDataInputStream in = fs.open(new Path(dfsPath));
接着客戶端對這個輸入流調用read()方法讀取,存儲着文件起始位置的幾個塊的DataNode地址的DFSInputStream隨機鏈接距離最近的DataNode。通過
對數據流反復調用read()方法,將數據從DataNode傳輸到客戶端,到達快的末端時,DFSInputStream關閉與該DataNode的連接,然后尋找下一個塊的
最佳DataNode,客戶端只需要讀取連續的流。客戶端從流中讀取數據時,塊是按照打開DFSInputStream與DataNode新建連接順序的讀取的,它也會根
據需要詢問NameNode來檢索下一批數據塊的DataNode的位置,一旦客戶端讀取完成就對DFSInputStream調用close()方法釋放。在讀取數據時,如果
DFSInputStream在與DataNode通信時遇到錯誤,會嘗試從這個塊的另外一個最鄰近的DataNode讀取數據。它也會記住那個故障的DataNode,以保證
以后不會從那個故障DataNode節點反復讀取后續的塊數據。DFSInputStream也會通過校驗和確認從DataNode發來的數據是否完整。如果發現有損壞的
塊,就在DFSInputStream試圖從其他DataNode讀取其副本之前通知NameNode。這個設計的一個重點是:NameNode告知客戶端每個塊中最佳的
DataNode,並讓客戶端直接連接到該最佳DataNode上檢索數據。由於數據流分散在集群中的所有DataNode上,所以這種設計能使HDFS可擴展到大量
的並發客戶端。同時,NameNode只需要響應塊位置的請求(這些塊位置信息存儲在內存中,因而非常高效),無需響應數據請求,否則隨着客戶端數量
的增長,NameNode會很快成為瓶頸。
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(new File(localPath)));
IOUtils.copyBytes(in, out, 4096, true);
Hadoop的網絡拓撲解釋
在本地網絡中,兩個節點被稱為“彼此近鄰”是指:在海里數據處理中,其主要限制因素是節點之間數據的傳輸速率-帶寬很稀缺。這里的想法是將兩個
節點間的帶寬作為軍力的衡量標准。如果不用衡量節點間的帶寬則很難實現(需要一個穩定的集群,並且在集群中兩兩節點對數量是節點數量的平方)。
Hadoop為此采用了一種簡單的方法:把網絡當做一棵樹,兩個節點間的距離是它們到最近共同祖先的距離綜合。該書中的層次是沒有預先設定的,但是相對
於數據中心、機架和正在運行的節點,通常可以設定等級。具體是針對以下每個場景,可用帶寬一次遞減,如下:
同一節點上的進程
同一機架上的不同節點
同一數據中心的不同機架上的節點
不同數據中心的節點
跨數據中心運行
目前到Hadoop-2.7仍然不適合跨數據中心運行。