Hadoop基礎之RPC機制以及HDFS源碼分析

1.RPC機制

1.1.概述

RPC——遠程過程調用協議,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,爲通信程序之間攜帶信息數據。在OSI網絡通信模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分佈式多程序在內的應用程序更加容易。
RPC採用客戶機/服務器模式。請求程序就是一個客戶機,而服務提供程序就是一個服務器。首先,客戶機調用進程發送一個有進程參數的調用信息到服務進程,然後等待應答信息。在服務器端,進程保持睡眠狀態直到調用信息的到達爲止。當一個調用信息到達,服務器獲得進程參數,計算結果,發送答覆信息,然後等待下一個調用信息,最後,客戶端調用進程接收答覆信息,獲得進程結果,然後調用執行繼續進行。

1.2.調用過程

1.3.代碼實現

[java] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. package mavshuang.rpc; 
  2. import org.apache.hadoop.ipc.VersionedProtocol; 
  3. public interface MyBizable extends VersionedProtocol { 
  4.     public static final long VERSION = 123456L; 
  5.     public abstract String hello(String name); 

 

[java] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. package mavshuang.rpc;import java.io.IOException; 
  2. public class MyBiz implements MyBizable { 
  3. public long getProtocolVersion(String protocol , long clientVersion) throws IOException { 
  4.         return MyBizable.VERSION; 
  5.     } 
  6.     public String hello(String name) { 
  7.         System.out.println("我被調用了!"); 
  8.         return "hello" +name; 
  9.     } 

 

[java] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. package mavshuang.rpc; 
  2. import java.net.InetSocketAddress; 
  3. import org.apache.hadoop.conf.Configuration; 
  4. import org.apache.hadoop.ipc.RPC; 
  5. public class MyClient { 
  6.     public static void main(String[] args) throws Exception { 
  7.         final MyBizable proxy = (MyBizable) RPC.waitForProxy(MyBizable.class, MyBizable.VERSION, new InetSocketAddress(MyServer.SERVER_IP, MyServer.SERVER_PORT), new Configuration()); 
  8.         String result = proxy.hello("world,hello mavs!"); 
  9.         System.out.println("客戶端返回的結果:" + result); 
  10.         RPC.stopProxy(proxy); // 關閉網絡連接 
  11.     } 

說明:RPC.getProxy(),該方法有四個參數,第一個參數是被調用的接口類,第二個是客戶端版本號,第三個是服務端地址。返回的代理對象,就是服務端對象的代理,內部就是使用 java.lang.Proxy 實現的。

[java] view plaincopyprint?在CODE上查看代碼片派生到我的代碼片
  1. package mavshuang.rpc; 
  2. import org.apache.hadoop.conf.Configuration; 
  3. import org.apache.hadoop.ipc.RPC; 
  4. import org.apache.hadoop.ipc.RPC.Server; 
  5. public class MyServer { 
  6.     public static final String SERVER_IP = "localhost";// 指定服務器IP 
  7.     public static final int SERVER_PORT = 9999;// 指定服務器端口 
  8.     public static void main(String[] args) throws Exception { 
  9.         /** 
  10.          * 構造一個 RPC 服務端. 
  11.          *  
  12.          * @param instance 
  13.          *            實例對象中的方法會被客戶端調用 
  14.          * @param bindAddress 
  15.          *            the address to bind on to listen for connection:監聽連接的IP地址 
  16.          * @param port 
  17.          *            the port to listen for connections on:監聽連接的端口號 
  18.          * @param conf 
  19.          *            the configuration to use:使用的確認協議 
  20.          */ 
  21.         final Server server = RPC.getServer(new MyBiz(), SERVER_IP, SERVER_PORT, new Configuration()); 
  22.         server.start();// 啓動服務 
  23.     } 

說明:RPC.getServer 方法,該方法有四個參數,第一個參數是被調用的 java對象,第二個參數是服務器的地址,第三個參數是服務器的端口。獲得服務器對象後,啓動服務器。這樣,服務器就在指定端口監聽客戶端的請求。
運行時,先啓動服務端,再啓動客戶端,運行結果:


命令行執行 jps 命令,查看輸出信息:
 

2.HDFS的分佈式存儲架構的源碼分析

2.1.NameNode的接口分析


由上圖可以看到NameNode本身就是一個java進程。 觀察上圖中RPC.getServer()方法的第一個參數,發現是 this,說明 NameNode 本身就是一個位於服務端的被調用對象,即 NameNode 中的方法是可以被客戶端代碼調用的。根據 RPC 運行原理可知,NameNode暴露給客戶端的方法是位於接口中的。

查看 NameNode 的源碼,如下圖所示 

可以看到 NameNode 實現了 ClientProtocal、DatanodeProtocal、NamenodeProtocal 等接口。下面逐一分析這些接口。
(1)DFSClient調用ClientProtocal
這個接口是供客戶端調用的。這裏的客戶端不是指的自己寫的代碼,而是hadoop 的一個類叫做 DFSClient。在 DFSClient 中會調用 ClientProtocal 中的方法, 完成一些操作。
該接口中的方法大部分是對 HDFS 的操作,如 create、delete、mkdirs、rename 等。
(2)DataNode調用DatanodeProtocal
這個接口是供 DataNode 調用的。 DataNode 調用該接口中的方法向 NameNode 報告本節點的狀態和 block 信息。
NameNode 不能向 DataNode 發送消息,只能通過該接口中方法的返回值向DataNode 傳遞消息。
(3)SecondaryNameNode調用NamenodeProtocal
這個接口是供 SecondaryNameNode 調用的。SecondaryNameNode 是專門做NameNode 中 edits 文件向 fsimage 合併數據的。

2.2. DataNode的接口分析

按照分析 NameNode 的思路,看一下 DataNode 的源碼接口。

 
這裏有兩個接口,分別是 InterDatanodeProtocal、ClientDatanodeProtocal。

2.3. HDFS的寫數據過程分析

通過FileSystem類可以操控HDFS,那麼從這裏開始分析寫數據到HDFS的過程。
在向 HDFS 寫文件的時候,調用的是 FileSystem.create(Path path)方法,查看這個方法的源碼,通過跟蹤內部的重載方法,可以找到如下圖所示的調用。

這個方法是抽象類,沒有實現。那麼只能向他的子類尋找實現。FileSystem 有個子類是 DistributedFileSystem,在的僞分佈環境下使用的就是這個類。可以看到
DistributedFileSystem 的這個方法的實現,如圖所示。
 
在上圖中,注意第 185 行的返回值 FSDataOutputStream。這個返回值對象調用了自己的構造方法, 構造方法的第一個參數是 dfs.create()方法。關注一下這裏的 dfs 對象是誰,create 方法做了什麼事情。現在進入這個方法的實現,如下圖所示。

在上圖中,返回值正是第 713 行創建的對象。繼續查看該方法:

 
在上圖中,可 以 看 到,這 個 類 是 DFSClient 的 內 部 類 。 在 類 內 部 通 過 調用namenode.create()方法創建了一個輸出流。再看一下 namenode 對象是什麼類型,如下圖所示:

在上圖中,可以看到 namenode 其實是 ClientProtocal 接口。那麼,這個對象是什麼時候創建?如下圖所示。

 
 
可以發現,namenode 對象是在 DFSClient 的構造函數調用時創建的,即當 DFSClient 對象存在的時候,namenode 對象已經存在了。
至此,可以看到,使用 FileSystem 對象的 api 操縱 HDFS,其實是通過 DFSClient 對象訪問 NameNode 中的方法操縱 HDFS 的。這裏的 DFSClient 是 RPC 機制的客戶端, NameNode是 RPC 機制的服務端的調用對象,整個調用過程如下圖所示。

在整個過程中,DFSClient 是個很重要的類,從名稱就可以看出,它表示 HDFS 的 Client,是整個 HDFS 的 RPC 機制的客戶端部分。對 HDFS 的操作,是通過 FileSsytem 調用的DFSClient 裏面的方法。FileSystem 是封裝了對 DFSClient 的操作,提供給用戶使用的。

2.4. HDFS的讀數據過程分析

繼續在 FileSystem 類分析,讀數據使用的是 open(…)方法,可以看到源碼,如下圖所示。

 

在上圖中,返回的是 DFSClient 類中 DFSDataInputStream 類,顯而易見,這是一個內部類。這個內部類的構造函數,有兩個形參,第一個參數是 dfs.open(…)創建的對象。看一下方法的源碼,如下圖所示。

 
在上圖的實現中,返回的是一個 DFSInputStream 對象。該對象中含有 NameNode 中的數據塊信息。看一下DFSInputStream類的構造方法源碼,如下圖所示。

在上圖中,這個構造方法中最重要的語句是第 1834 行,打開信息,從第 1840 行開始是 openInfo()的源代碼,截圖顯示不全。注意第 1841 行,是獲取數據塊的信息的。查看這一行的源代碼,如下圖所示。

 從上圖中可以看到,獲取數據塊信息的方法也是通過調用 namenode 取得的。這裏的 namenode 屬性還是位於 DFSClient 中的。通過前面的分析,已經知道,在DFSClient類中的 namenode 屬性是 ClientProtocal。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章