Hadoop RPC
对外主要提供了两种接口(见类org.apache.hadoop.ipc.RPC),分别是:
public static ProtocolProxy getProxy/waitForProxy(…)
:构造一个客户端代理对象(该对象实现了某个协议),用于向服务器发送RPC请求。public static Server RPC.Builder (Configuration).build()
:为某个协议(实际上是Java接口)实例构造一个服务器对象,用于处理客户端发送的请求。
关于上述二者源码将在下节介绍,本节介绍使用上述两个方法构造的RPC测试用例。通常而言,使用Hadoop RPC可分为以下4个步骤。
1. 定义RPC协议
RPC协议是客户端和服务器端之间的通信接口,它定义了服务器端对外提供的服务接口。如ClientProtocol
通信接口。需要注意的是,Hadoop中所有自定义RPC接口都需要继承VersionedProtocol接口(高版本中已没有强制要求了,如2.7版本),它描述了协议的版本信息。
2. 实现RPC协议
Hadoop RPC
协议通常是一个Java接口,用户需要实现该接口。如源码对ClientProtocol接口的实现。
3. 构造并启动RPC Server
直接使用静态类Builder构造一个RPC Server,并调用函数start()启动该Server。
4. 构造RPC Client并发送RPC请求
使用静态方法getProxy构造客户端代理对象,直接通过代理对象调用远程端的方法。
经过以上四步,我们便利用Hadoop RPC搭建了一个非常高效的客户机–服务器网络模型。接下来,我们用具体代码来看上述的实现。
代码实现
(1) 定义协议
MyProxyProtocol.java
public interface MyProxyProtocol extends VersionedProtocol{
// versionID for client and server sould be consistent
public static final long versionID = 1L;
public String hello(String msg) throws IOException;
}
(2)实现协议
MyProxy.java
public class MyProxy implements MyProxyProtocol {
@Override
public String hello(String msg) throws IOException {
return "Hello: " + msg;
}
@Override
public long getProtocolVersion(String protocol, long clientVersion) throws IOException {
return versionID;
}
@Override
public ProtocolSignature getProtocolSignature(String protocol, long clientVersion, int clientMethodsHash) throws IOException {
return new ProtocolSignature(versionID,null);
}
}
(3) 构造并启动Server
MyServer.java
public class MyServer {
private static String HOST = "localhost";
private static final int PORT = 2181;
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
RPC.Server server = new RPC.Builder(conf).setProtocol(MyProxyProtocol.class)
.setInstance(new MyProxy())
.setBindAddress(HOST)
.setNumHandlers(2)
.setPort(PORT)
.build();
server.start();
}
}
(4) 客户端发送请求
MyClient.java
public class MyClient {
private static String HOST = "localhost";
private static final int PORT = 2181;
public static void main(String[] args) throws IOException {
Configuration conf = new Configuration();
MyProxyProtocol proxy = RPC.getProxy(MyProxyProtocol.class,
MyProxyProtocol.versionID,
new InetSocketAddress(HOST, PORT), conf);
String result = proxy.hello("didi");
System.out.println(result);
}
}
启动server和client,可以看到结果:
server:
2019-05-30 18:24:43,867 INFO ipc.CallQueueManager (CallQueueManager.java:<init>(53)) - Using callQueue class java.util.concurrent.LinkedBlockingQueue
2019-05-30 18:24:44,244 INFO ipc.Server (Server.java:run(709)) - Starting Socket Reader #1 for port 2181
2019-05-30 18:24:44,581 WARN util.NativeCodeLoader (NativeCodeLoader.java:<clinit>(62)) - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
2019-05-30 18:24:44,663 INFO ipc.Server (Server.java:run(939)) - IPC Server Responder: starting
2019-05-30 18:24:44,663 INFO ipc.Server (Server.java:run(779)) - IPC Server listener on 2181: starting
2019-05-30 18:24:50,640 INFO security.IP2UsersBlackList (IP2UsersBlackList.java:reload(142)) - BlackList checking enable: false
2019-05-30 18:24:50,653 INFO security.IP2UsersWhiteList (IP2UsersWhiteList.java:reload(142)) - WhiteList checking enable: false
2019-05-30 18:24:50,662 INFO security.PasswordManager (PasswordManager.java:reload(163)) - Password checking enable: false
client:
2019-05-30 18:24:50,246 WARN util.NativeCodeLoader (NativeCodeLoader.java:<clinit>(62)) - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Hello: didi
分析:上述代码中,在客户端主要有RPC.getProxy
方法获得代理;在服务端主要有RPC.Builder
。关于二者的核心分析,将在下节介绍。