Hadoop 的 RPC 通信实例
2019-06-05
关键字:Hadoop、Hadoop RPC 实例、Hadoop RPC 调用、Hadoop 远程过程调用
本篇文章简要介绍一下 RPC 的概念,并给出 Hadoop 中的一个 RPC 开发实例。
RPC 的概念
RPC 是一种通过网络从远程计算机上请求服务但不需要关心底层的网络通信细节的通信协议。简单来说,RPC 是一种通信协议。
RPC 是基于 TCP 或 UDP 之上构建的通信过程。正是因为 RPC 不需要花费精力去处理底层网络通信细节,可以完全专注于通信业务逻辑的特点,它在分布式领域里得到了广泛的应用。
RPC 的架构模型通常为 C/S 模型。一个典型的 RPC 结构组成有如下几个部分
1、通信模块
通信模块就是用于在网络上传输数据包的,它一般不会对数据包内容作任何处理。 RPC 的通信有同步和异步两种通信模式。
2、Stub 程序
可以简单理解成是一个代理。它上面记载了所有支持的远程调用接口,服务端和客户端各自持有一份完全相同的 Stub 程序。我们的 RPC 的过程,其本质上就是去调用各自手里的这份 Stub 程序上的接口而已。
3、调度程序
调度器,运行在服务端。接收来自通信模块的请求,并根据请求中的标识符来选择对应的 Stub 程序去执行。
RPC 通信的过程
下面介绍一个典型的 RPC 通信过程
步骤一:客户端调用自己手里的 Stub 程序上相应的接口;
步骤二:客户端侧的 Stub 程序将调用请求信息按照网络通信模块的要求封装成消息包,并交给通信模块以发送到远程服务端;
步骤三:远程服务端的通信模块在接收到消息包以后会将此消息包转发给调度程序;
步骤四:调度程序会根据消息包中的标识符,再将消息转发给相关的服务端侧的 Stub 程序;
步骤五:服务端侧的 Stub 程序会拆封消息包,形成被调过程的形式,并去调用对应的方法函数;
步骤六:被调用的函数会按照所获参数执行,并将最终结果返回给 Stub 程序;
步骤七:服务端侧的 Stub 程序会将返回的结果打包成消息包,通过网络通信模块逐级地传送给客户端程序。
以下是上述步骤的框架图
Hadoop RPC 实例
Hadoop 虽然是使用 Java 语言开发的,但它的 RPC 框架却没有直接沿用 Java 的 RPC 框架。但总体而言差异也并不大,开发过程也比较简单。
下面做一个简单的 Hadoop RPC 程序小实例。
步骤一
Hadoop 的所有自定义 RPC 接口都需要继承 org.apache.hadoop.ipc.VersionedProtocol 接口。这里我们来定义一个实现两个数相加的接口。
import org.apache.hadoop.ipc.VersionedProtocol; public interface IRPCDemo extends VersionedProtocol { int myAdd(int a, int b); }
步骤二
接下来,我们要创建 RPC 的服务端。需要实现在步骤一中定义的接口。
import java.io.IOException; import org.apache.hadoop.ipc.ProtocolSignature; public class RPCDemoImpl implements IRPCDemo { @Override public long getProtocolVersion(String protocol, long clientVersion) throws IOException { return 0; } @Override public ProtocolSignature getProtocolSignature(String protocol, long clientVersion, int clientMethodsHash) throws IOException { try { return ProtocolSignature.getProtocolSignature(protocol, clientVersion); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } @Override public int myAdd(int a, int b) { if(a < 0 || b < 0) return 0; return a + b; } }
这里解释一下上面的两个方法。
关于 getProtocolVersion() 方法,它返回一个版本号。RPC 通信对于版本号要求很严格,版本号不同一定不能通信。在生产环境中需要严肃对待这个方法的返回值,但在我们的示例程序里就无所谓了。
关于中间那个 getProtocolSignature() 方法,照着写就好了。
步骤三
接着来实现我们的服务端。
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; import org.apache.hadoop.ipc.RPC.Server; public class RPCDemoServer { public static void main(String[] args) { Configuration conf = new Configuration(); try { Server server = new RPC.Builder(conf) .setBindAddress("usmaster") .setNumHandlers(2) .setPort(17173) .setInstance(new RPCDemoImpl()) .setProtocol(IRPCDemo.class) .build(); server.start(); } catch (Exception e) { e.printStackTrace(); } } }
其实也没什么特别的,照着写就好了。上面注意要把自己的服务端接口实现类和服务端接口类给替换一下。即上面代码标红部分。
步骤四
然后是来实现我们的客户端程序。
import java.io.IOException; import java.net.InetSocketAddress; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; public class RPCDemoClient { public static void main(String[] args) { Configuration conf = new Configuration(); try { IRPCDemo lmt = RPC.getProxy(IRPCDemo.class, 0, new InetSocketAddress("usmaster", 17173), conf); int ret = lmt.myAdd(3, 7); System.out.println(ret); ret = lmt.myAdd(-3, 1); System.out.println(ret); } catch (IOException e) { e.printStackTrace(); } } }
至此,我们的 Hadoop 版 RPC 实例就完成了。如果想要测试的话,在确保了相关 Hadoop 环境正确以后就可以直接运行 Server 端和 Client 端来查看结果了。