RPC简介与Thrift框架

时间:2022-02-10 08:26:55

     RPC(Remote Process Call Protocal),远程过程调用协议,是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。

     RPC采用客户机/服务器模式,请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息。最后,客户端调用进程接收答复信息,获得进程结果。客户端和服务器之间建立TCP连接,远程过程调用所有交换的数据都在这个连接里传输。连接可以是短连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。

     以下是一个RPC调用的通信流程图:


RPC简介与Thrift框架

1)服务消费方(client)以本地调用方式调用服务;

2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;

3)client stub找到服务地址,并将消息发送到服务端;

4)server stub收到消息后进行解码;

5)server stub根据解码结果调用本地的服务;

6)本地服务执行并将结果返回给server stub;

7)server stub将返回结果打包成消息并发送至消费方;

8)client stub接收到消息,并进行解码;

9)服务消费方得到最终结果。

RPC框架就是把2~8步封装起来。

常见的RPC框架:

1.RMI,Remote Method Invocation,远程方法调用。这个是Java原生的API,能够让在某个Java虚拟机中的对象调用另一个Java虚拟机中对象的方法,使用时不需要引入其他任何第三方jar包,但是要求客户端代码和服务端代码都要用Java语言编写,而且速度太慢,基本没有人用。

2.Thrift,Facebook开源并被Apache孵化。是一个跨语言的框架,客户端代码和服务端代码可以用不通的语言编写。

3.Dubbo,阿里巴巴开源,是使用最广泛的一个,但是在2012年就停止维护了。

4.HSF,可以翻译为“好舒服”,阿里巴巴最新的RPC框架。

下面用RMI和Thrift这两种框架实现一个简单的功能:

一个服务器上部署一个服务,客户端调用的时候,返回欢迎信息。

RMI实现

编写步骤:

1.定义一个继承Remote远程接口的接口,该接口中的每一个方法都必须声明抛出RemoteException异常。

2.

 

 

Thrift框架简单使用示例:

我们首先需要写一个thrift文件,其实就是个service定义文件,内容如下:

 

namespace java com.kou.test
service Hello{
string sayHello(1:string username)
}

namespace指定包名,service是接口的关键字,Hello是service名,sayHello是方法名。文件名无所谓,但为了方便管理,最好和接口同名。

 

之后,再下载thrift的代码生成工具thrift-xxx.exe,放到和thrift文件同一目录下,然后在该目录中在命令行窗口执行

thrift --gen <language> <Thrift filename>

language是要生成的代码语言,thrift支持多种语言。

 

具体就是thrift --gen java Hello.thrift,执行之后就会在当前目录中产生一个名叫gen-java的文件夹,把文件夹中的代码文件拷贝到服务端web应用对应的包中。简单看一下这个文件,会发现原来的service名现在变成了类名,原来的sayHello方法跑到了Hello类的内部接口Iface中。

服务端发布RPC服务:

需要在服务端实现这个接口,所以新建一个类,实现Iface接口,重写其sayHello方法,代码如下:

 

import org.apache.thrift.TException;

import com.kou.test.Hello.Iface;

public class HelloImpl implements Iface {
@Override
public String sayHello(String username) throws TException {
return "hello," + username;
}
}

如何启动服务呢,新建一个类,创建启动方法即可。

 

启动服务代码如下(不用记,套路基本固定):

 

public class HelloThriftServer {

@SuppressWarnings({ "rawtypes", "unchecked" })
public void startServer() {
try {
TServer.Args tArgs = new TServer.Args(new TServerSocket(8090));
TProcessor tprocessor = new Hello.Processor(new HelloImpl());
tArgs.processor(tprocessor);
tArgs.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new TSimpleServer(tArgs);
server.serve();
} catch (Exception e) {
e.printStackTrace();
}
}
}

 

至此,服务端代码已完成,可以部署了。我们在此应用中配置一个监听器,当应用一启动的时候就调用HelloThriftServer实例的startServer()方法开启服务,待客户端调用。

监听器代码如下:

 

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import com.kou.test.HelloThriftServer;

/**
* Application Lifecycle Listener implementation class ThriftListener
*
*/
public class ThriftListener implements ServletContextListener {

/**
* Default constructor.
*/
public ThriftListener() {
// TODO Auto-generated constructor stub
}

@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub

}

@Override
public void contextInitialized(ServletContextEvent arg0) {
new HelloThriftServer().startServer();
}
}

把应用部署到Tomcat中之后即可以接受客户端的调用了。至此,RPC服务发布完成了。

 

客户端调用:

客户端调用服务端的服务,只需知道服务端的ip和端口就好了(我们在上面的服务端代码中指定了端口是8090)。

客户端和服务端一样,都需要上面用thrift代码生成工具生成的java文件,复制到客户端web应用对应的包中,然后新建一个类,写调用服务的方法,代码如下(不用记,套路基本固定):

 

import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

import com.kou.test.Hello.Client;

public class HelloThriftClient {
public void invokeHelloThrift(String userName) {
TTransport tTransport = null;
try {
// 服务端的ip和端口
tTransport = new TSocket("192.168.153.128", 8090, 30000);
TProtocol protocol = new TBinaryProtocol(tTransport);
Client client = new Client(protocol);
tTransport.open();
// 调用接口方法
String str = client.sayHello(userName);
System.out.println(str);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != tTransport) {
tTransport.close();
}
}
}

/**
* @param args
*/
public static void main(String[] args) {
new HelloThriftClient().startClient("寇胜瑞");
}
}

此时,客户端应用就可以用invokeHelloThrift()方法来调用RPC服务了。这里我们通过简单的main方法来测试是否可以成功调用。