Hadoop RPC的機制分析和源碼解讀

Hadoop RPC是Hadoop的一個重要部分,提供分佈式環境下的對象調用功能,源碼在org.apache.hadoop.ipc中。而HBase也幾乎完全copy了這部分的源碼,只是在配置項上面有所改動。

關於Hadoop RPC的機制分析和源碼解讀,網上已經有許多資料,一搜一大把,這裏就不在描述了。本文通過一個小例子,介紹如何調用Hadoop RPC。

1. 應用場景

Hadoop RPC在整個Hadoop中應用非常廣泛,Client、DataNode、NameNode之間的通訊全靠它了。

舉個例子,我們平時操作HDFS的時候,使用的是FileSystem類,它的內部有個DFSClient對象,這個對象負責與NameNode打交道。在運行時,DFSClient在本地創建一個NameNode的代理,然後就操作這個代理,這個代理就會通過網絡,遠程調用到NameNode的方法,也能返回值。

在我的應用場景中,需要一個元數據服務器,各節點經常需要去查詢元數據,可以使用這套RPC機制。

2. Protocol

被遠程訪問的類,也就是Server端,必須實現VersionedProtocol接口,這個接口只有一個方法getProtocolVersion,用來判斷Server和Client端調用的是不是一個版本的,一般Server的代碼修改一次,版本號就得改一次。

在例子中,我們定義一個接口MyProtocol,繼承VersionedProtocol,裏面定義Server端需要實現的方法。

這裏MyProtocol接口只有一個方法println,輸入一個Text,打印出來,並返回一個Text。

MyProtocol.java代碼如下:

複製代碼
1 import org.apache.hadoop.io.Text;
2 import org.apache.hadoop.ipc.VersionedProtocol;
3 
4 public interface MyProtocol extends VersionedProtocol {
5     public Text println(Text t);
6 }
複製代碼

3. Server

Server端實現上述的Protocol接口,裏面需要啓動一個RPC.Server,它是一個Thread。

構造方法是RPC.getServer(Object instance, String bindAddress, int port, Configuration conf)

  • instance:表示提供遠程訪問的對象,一般Server都會傳入this作爲參數;
  • bindAddress:Server綁定的ip地址;
  • port:Server綁定的端口;
  • conf:Configuration對象,不用解釋了吧。

MyServer實現了MyProtocol接口中定義的println方法,將參數打印到控制檯,並返回finish。

MyServer.java代碼如下:

複製代碼
 1 import java.io.IOException;
 2 import java.net.UnknownHostException;
 3 
 4 import org.apache.hadoop.conf.Configuration;
 5 import org.apache.hadoop.io.Text;
 6 import org.apache.hadoop.ipc.RPC;
 7 import org.apache.hadoop.ipc.RPC.Server;
 8 
 9 public class MyServer implements MyProtocol{
10     private Server server;
11     
12     public MyServer(){
13         try {
14             server = RPC.getServer(this, "localhost", 8888, new Configuration());
15             server.start();
16             server.join();
17         } catch (UnknownHostException e) {
18             e.printStackTrace();
19         } catch (IOException e) {
20             e.printStackTrace();
21         } catch (InterruptedException e) {
22             e.printStackTrace();
23         }
24     }
25     
26     @Override
27     public Text println(Text t){
28         System.out.println(t);
29         return new Text("finish");
30     }
31 
32     @Override
33     public long getProtocolVersion(String protocol, long clientVersion) throws IOException {
34         return 1;
35     }
36     
37     public static void main(String[] args) {
38         new MyServer();
39     }
40 
41 }
複製代碼

4. Client

Client端需要創建一個Server的遠程代理,並可以通過操作這個代理,來調用到Server端的方法。

創建代理可以調用RPC.waitForProxy(Class protocol, long clientVersion, InetSocketAddress addr, Configuration conf)

  • protocol:一個Protocol的class,它必須是繼承VersionedProtocol的接口;
  • clientVersion:客戶端的版本號,如果與服務端不一致,則會拋錯;
  • addr:一個InetSocketAddress對象,包含了ip和port;
  • conf:不解釋。

這個方法會返回一個VersionedProtocol類型的代理對象,將它強制轉型成自己定義的Protocol,接下來就可以操作創建好的代理了。在例子中,我們通過代理來讓Server端打印字符串到控制檯,並接受返回的消息。

MyClient.java代碼如下:

複製代碼
 1 import java.io.IOException;
 2 import java.net.InetSocketAddress;
 3 
 4 import org.apache.hadoop.conf.Configuration;
 5 import org.apache.hadoop.io.Text;
 6 import org.apache.hadoop.ipc.RPC;
 7 
 8 public class MyClient {
 9     
10     private MyProtocol proxy;
11 
12     public MyClient(){
13         InetSocketAddress addr = new InetSocketAddress("localhost",8888);
14         try {
15             proxy = (MyProtocol) RPC.waitForProxy(MyProtocol.class, 1, addr , new Configuration());
16         } catch (IOException e) {
17             e.printStackTrace();
18         }
19     }
20     
21     public void println(String s){
22         System.out.println(proxy.println(new Text(s)));
23     }
24 
25     public void close(){
26         RPC.stopProxy(proxy);
27     }
28     
29     public static void main(String[] args) {
30         MyClient c = new MyClient();
31         c.println("123");
32         c.close();
33     }
34 }
複製代碼

 5. 運行

運行MyServer,控制檯顯示:

2011-12-30 18:49:56 -[INFO] Initializing RPC Metrics with hostName=MyServer, port=8888
2011-12-30 18:49:56 -[INFO] IPC Server listener on 8888: starting
2011-12-30 18:49:56 -[INFO] IPC Server Responder: starting
2011-12-30 18:49:56 -[INFO] IPC Server handler 0 on 8888: starting

運行MyClient,控制檯顯示:

finish

MyServer端會追加顯示:

123 

發佈了35 篇原創文章 · 獲贊 13 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章