概念
RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行
hadoop RPC介绍
为什么会引入RPC:
RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。当我们讨论HDFS的,通信可能发生在:
- Client-NameNode之间,其中NameNode是服务器
- Client-DataNode之间,其中DataNode是服务器
- DataNode-NameNode之间,其中NameNode是服务器
- DataNode-DateNode之间,其中某一个DateNode是服务器,另一个是客户端
如果我们考虑Hadoop的Map/Reduce以后,这些系统间的通信就更复杂了。为了解决这些客户机/服务器之间的通信,Hadoop引入了一个RPC框架。
Hadoop的RPC的特点:
RPC是分布式计算中C/S模型的一个应用实例,对于Hadoop而言,他有以下几个特点:
- 透明性
- 高性能
- 可控性:
Hadoop的RPC的总体架构:
hadoop RPC主要分为四个部分:序列化层,函数调用层,网络传输层,服务端处理框架。
- 序列化层
序列化的主要作用是将结构化对象转换为字节流以便通过网络进行传输或者写入持久存储。在RPC框架中,它主要用于将用户请求中的参数或者应答转换成字节流以便跨机传输。
- 函数调用层
函数调用层主要功能是:定位要调用的函数,并执行该函数,Hadoop采用了java的反射机制和动态代理实现了函数的调用。
- 网络传输层
网络传输层描述了Client和Server之间消息的传输方式,Hadoop采用了基于TCP/IP的socket机制。
服务端处理框架
服务端处理框架可被抽象为网络I/O处理模型,她描述了客户端和服务器端信息交互的方式,她的设计直接决定了服务器端的并发处理能力。常见的网络I/O模型有阻塞式I/O,非阻塞式I/O、事件驱动式I/O等,而Hadoop采用了基于reactor设计模式的事件驱动I/O模型
HadoopRPC的使用方法:
HadoopRPC主要提供了两种接口
- public static T getProxy/waitForProxy(Class protocol,longclientVersion,InetSocketAddress addr, Configuration conf,SocketFactory factory) throws IOException;
用于构造客户端代理对象(该对象实现了某个协议),用于向服务器端发送RPC请求。
- public static Server RPC.Builder(Configuration).build();
为某个协议(java接口)实例构造服务器对象,用于客户端处理发送的请求。
通常,使用Hadoop 的RPC 可分为一下4个步骤:
- 定义RPC协议
- 实现RPC协议
- 构造并启动RPC Server
- 构造RPC Client 并发发送RPC请求
经过以上四部,我们便利用了Hadoop搭建了一个非常高效的c/s网络模型。
代码实现一个简单的hadoop RPC
需求:服务端有一个服务需要远程调用,这个服务中有三个方法:创建连接的方法/心跳机制的方法/远程数字计算(求和)的方法, 要求使用RPC完成客户端远程调用
- 定义RPC协议
package testrpc.MyProtocol;
import org.apache.hadoop.ipc.VersionedProtocol;
import testrpc.connectionpojo.ConnectionStatus;
/**
创建一个协议的接口,server端真正需要被远程调用的服务需要实现这个接口
*这个接口需要实现RPC的顶级的父类VersionedProtocol的类,让这个接口可以实现RPC的通信
*/
public interface MyProtocol extends VersionedProtocol {
//定义一个协议的版本,注意这里有坑,这个属性的名字必须是versionID,因为源码中默认就是通过反射调用的这个名字的属性
//更改成其他的都是不行的********
long versionID=1L;
//创建几个方法来供远程来调用
//创建一个链接的方法来供client来连接,返回值是一个字符串,接收一个字符串的命令
ConnectionStatus connection(String command);
//创建一个心跳的方法,来供客户端和服务端采用心跳机制来保障连接客户端输入一个字符串的心跳报文,服务端接收到之后返回
String HeatBeat(String command_HeartBeant);
//这里模拟一个其他的功能,比如说在服务端有一个计算的服务,用来计算两个数的和,只需要客户端将两个数字串过来就行,将结果自动返回去
int Add(int num1,int num2);
}
- 实现RPC协议
package testrpc.MyProtocol;
import org.apache.hadoop.ipc.ProtocolSignature;
import testrpc.connectionpojo.ConnectionStatus;
import java.io.IOException;
public class MyProtocolImpl implements MyProtocol {
private boolean connectionStatus = false;
/**
* 这是实现的自定义的MyProtocol的协议的方法的具体的实现
* 完成客户端输入连接的指令,服务端判断之后返回相应的值
*/
@Override
public ConnectionStatus connection(String command) {
ConnectionStatus conn = new ConnectionStatus();
String response = null;
if