從上一篇文章中我們已經知道了NameNode和Secondary NameNode的職責,這篇文章我們主要講講我們怎么往DataNode上寫數據和讀數據。
DataNode的寫操作流程
DataNode的寫操作流程可以分為兩部分,第一部分是寫操作之前的準備工作,包括與NameNode的通信等;第二部分是真正的寫操作。我們先看第一部分。

- 首先,HDFS client會去詢問NameNode,看哪些DataNode可以存儲Block A-file.txt文件的拆分是在HDFS client中完成的,拆分成了3個Block (A,B,C)。因為NameNode存儲著整個文件系統的元數據,它知道哪個DataNode上有空間可以存儲這個Block A。
- NameNode通過查看它的元數據信息,發現DataNode1,2,7上有空間可以存儲Block A,于是將此信息告訴HDFS Client。
- HDFS Client接到NameNode返回的DataNode列表信息后,它會直接聯系第一個DataNode-DataNode1,讓它準備好接收Block A - 實際上就是建立彼此間的TCP連接。然后將Block A和NameNode返回的所有關于DataNode的元數據一并傳給DataNode1.
- 在DataNode1與HDFS Client建立好TCP連接后,它會把HDFS Client要寫Block A的請求順序傳給DataNode2(在與HDFS Client建立好TCP連接后從HDFS Client獲得的DataNodeli信息),要求DataNode2也準備好接收Block A(建立DataNode2到DataNode1的TCP連接)。
- 同上,建立DataNode2到DataNode7的TCP連接。
- 當DataNode7準備好之后,它會通知DataNode2,表明可以開始接收Block A。
- 同理,當DataNode2準備好之后,它會通知DataNode1,表明可以開始接收Block A。
- 當HDFS Client接到DataNode1的成功反饋信息后,說明這3個DataNode都準備好了,HDFS Client就會開始往這三個DataNode寫入Block A。
下面這張圖片展示了HDFS Client如何往DataNode寫入Block A數據。

在DataNode1,2,7都準備好接收數據后,HDFS Client開始往DataNode1寫入Block A數據。同準備工作一樣,當DataNode1接收完Block A數據后,它會順序將Block A數據傳輸給DataNode2,然后DataNode2再傳輸給DataNode7. 每個DataNode在接收完Block A數據后,會發消息給NameNode,告訴它Block數據已經接收完畢,NameNode同時會根據它接收到的消息更新它保存的文件系統元數據信息。當Block A成功寫入3個DataNode之后,DataNode1會發送一個成功信息給HDFS Client,同時HDFS Client也會發一個Block A成功寫入的信息給NameNode。之后,HDFS Client才能開始繼續處理下一個Block-Block B。
機架感知
其實NameNode在挑選合適的DataNode去存儲Block的時候,不僅僅考慮了DataNode的存儲空間夠不夠,還會考慮這些DataNode在不在同一個機架上。這就需要NameNode必須知道所有的DataNode分別位于哪個機架上(所以也稱為機架感知)。當然,默認情況下NameNode是不會知道機架的存在的,也就是說,默認情況下,NameNode會認為所有的DataNode都在同一個機架上(/defaultRack)。除非我們在hdfs-site.xml里面配置topology.script.file.name選項,這個選項的值是一個可執行文件的位置,而該只執行文件的作用是將輸入的DataNode的ip地址按照一定規則計算,然后輸出它所在的機架的名字,如/rack1, /rack2之類。借助這個文件,NameNode就具備了機架感知了。當它在挑選DataNode去存儲Block的時候,它會遵循以下原則:
- 首先挑選跟HDFS Client所在的DataNode作為存放第一個Block副本的位置,如果HDFS Client不在任何一個DataNode上,比如說Hadoop集群外你自己的電腦,那么就任意選取一個DataNode。
- 其次,會借助NameNode的機架感知特性,選取跟第一個Block副本所在DataNode不同的機架上的任意一個DataNode來存放Block的第二個副本,比如說/rack2。Block的第三個副本也會存在這個/rack2上,但是是另外一個DataNode
- 最后,如果我們設置的副本的數量大于3,那么剩下的副本則隨意存儲在集群中。
所以,按照上面的原則,在HDFS Client進行Block的寫操作時,流程應該如下面圖所示:

DataNode的讀數據流程
最后,我們來看看HDFS Client是如何從DataNode讀取數據的。

如上圖所示,首先,HDFS Client會先去聯系NameNode,詢問file.txt總共分為幾個Block而且這些Block分別存放在哪些DataNode上。由于每個Block都會存在幾個副本,所以NameNode會把file.txt文件組成的Block所對應的所有DataNode列表都返回給HDFS Client。然后HDFS Client會選擇DataNode列表里的第一個DataNode去讀取對應的Block,比如由于Block A存儲在DataNode1,2,7,那么HDFS Client會到DataNode1去讀取Block A;Block C存儲在DataNode,7,8,9,那么HDFS Client就回到DataNode7去讀取Block C。