文章目錄
一、 HDFS 的IO操作
1.1 上傳文件
```
@Test
public void testUploadFile() throws Exception {
FileInputStream fis = new FileInputStream("D:" + File.separator + "Hadoop_Test.txt");
FSDataOutputStream fos = fs.create(new Path("/user/kino/idea/Hadoop_Test"));
IOUtils.copyBytes(fis, fos, conf);
IOUtils.closeStream(fos);
IOUtils.closeStream(fis);
}
```
1.2 文件下載(完整下載)
@Test
public void testDownloadFile() throws Exception {
/**
* Path: HDFS 文件系統上的文件路徑;
* bufferSize: 要使用的緩衝區的大小, 並不是要將文件下載多大, 默認 4K;
*/
FSDataInputStream fis = fs.open(new Path("/user/kino/input/hadoop-2.7.2.tar.gz"));
FileOutputStream fos = new FileOutputStream("D:\\hadoop-2.7.2.tar1.gz");
IOUtils.copyBytes(fis, fos, conf);
IOUtils.closeStream(fos);
IOUtils.closeStream(fis);
}
1.3 文件下載(分塊(Block)下載)
讀取大文件(超過 128M 的文件)
- 讀取第一塊(Block)
@Test public void testDownloadFileToBlockOne() throws Exception { /** * Path: HDFS 文件系統上的文件路徑; * bufferSize: 要使用的緩衝區的大小, 並不是要將文件下載多大, 默認 4K; */ FSDataInputStream fis = fs.open(new Path("/user/kino/input/hadoop-2.7.2.tar.gz")); FileOutputStream fos = new FileOutputStream("D:\\hadoop-2.7.2.tar1.gz"); byte[] b = new byte[1024]; for (int i = 0; i < 1024*128; i++) { fis.read(b); fos.write(b); } IOUtils.closeStream(fos); IOUtils.closeStream(fis); }
2. 讀取第二塊(Block)
@Test
public void testDownloadFileToBlockTwo() throws Exception {
/**
* Path: HDFS 文件系統上的文件路徑;
* bufferSize: 要使用的緩衝區的大小, 並不是要將文件下載多大, 默認 4K;
*/
FSDataInputStream fis = fs.open(new Path("/user/kino/input/hadoop-2.7.2.tar.gz"));
FileOutputStream fos = new FileOutputStream("D:\\hadoop-2.7.2.tar2.gz");
fis.seek(1024*1024*128);
IOUtils.copyBytes(fis, fos, conf);
IOUtils.closeStream(fos);
IOUtils.closeStream(fis);
}
在 window 中 合併兩個文件: type file1 >> file2
此時文件大小和 HDFS 系統上的文件大小一致, 修改名字成hadoop-2.7.2.tar.gz
後解壓後查看
二、 HDFS 寫數據流程
2.1 剖析文件寫入
HDFS 寫數據流程
- 客戶端通過 Distributed FileSystem 向 NameNode 請求上傳文件, NameNode 檢查目標文件是否已存在, 父目錄是否存在;
- 如果不存在, NameNode 返回可以上傳; 如果已經存在, NameNode 返回不可以上傳;
- 客戶端請求上傳第一塊數據, 詢問 NameNode可以上傳到哪些DataNode 服務器上;
- NameNode 返回 3個 DateNode 節點, 分別爲 dn1, dn2, dn3;
- 客戶端通過 FSDateOutputStream模塊請求 dn1 上傳數據, dn1 收到請求會繼續調用 dn2, 然後 dn2 調用 dn3, 將這個通信管道建立完成;
- dn1、dn2、dn3 逐級應答客戶端;
- 客戶端開始往dn1上傳第一個Block(先從磁盤讀取數據放到一個本地內存緩存),以Packet爲單位,dn1收到一個Packet就會傳給dn2,dn2傳給dn3;dn1每傳一個packet會放入一個應答隊列等待應答。
- 當一個Block傳輸完成之後,客戶端再次請求NameNode上傳第二個Block的服務器。(重複執行3-7步)。
2.2 網絡拓撲-節點距離計算
在HDFS寫數據的過程中,NameNode會選擇距離待上傳數據最近距離的DataNode接收數據。那麼這個最近距離怎麼計算呢?
節點距離:兩個節點到達最近的共同祖先的距離總和。
下圖中機架中的每個節點相當於一臺服務器,
例如,假設有數據中心d1機架r1中的節點n1。該節點可以表示爲/d1/r1/n1。利用這種標記,這裏給出四種距離描述,如下圖所示。
2.3 機架感知(副本存儲節點選擇)
-
For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on one node in the local rack, another on a different node in the local rack, and the last on a different node in a different rack.
-
Hadoop 副本節點選擇
思考: 爲什麼要這麼存?
三、 HDFS 讀數據流程
- 客戶端通過Distributed FileSystem向NameNode請求下載文件,NameNode通過查詢元數據,找到文件塊所在的DataNode地址。
- 挑選一臺DataNode(就近原則,然後隨機)服務器,請求讀取數據。
- DataNode開始傳輸數據給客戶端(從磁盤裏面讀取數據輸入流,以Packet爲單位來做校驗)。
- 客戶端以Packet爲單位接收,先在本地緩存,然後寫入目標文件。