这题目一看就是老标题党啦。既然Thrift是一个跨语言的RPC框架,所以本文采用Go和Java来实现,场景是Echo Server,实现十分简单,尽量呈现出Thrift使用的基本流程。
本文将基于Thrift,使用GO来实现一个Echo Server,使用Java来实现一个Echo Client。文中有不对的地方还望大家指出。
1、配置Thrift compiler
本文是在Win10环境下配置的,Thrift 版本是v0.13.0。Thrift compiler 用于编译Thrift脚本文件,生成各种语言的源文件,比如 Go,C++, Java, Python等,开发者将基于编译生成的源文件进行开发。
Thrift compiler 下载。
下载完成后,将thrift.exe文件放在任意文件夹就好了。
可以把当前文件夹添加进path环境变量,方便使用。
2、编写Thrift文件
使用Thrift 开发RPC服务需要编写Thrift脚本文件,使用的是Thrift接口定义语言 (IDL)。可以通过IDL在文件中定义一些变量,结构体,服务等。具体的语法可以参考官方文档,这里就不展开了。
如下代码块,建立一个echo.thrift文件。
namespace go echo
是命名空间,go
表示要应用于Go语言,echo
表示编译后的文件会在echo包下。
service
表示定义服务,编译后会生成Echo
这个接口,接口中有echoHello
这个方法,需要服务器端实现。
//echo.thrift
namespace go echo
namespace java echo
service Echo {
string echoHello(1: string name)
}
3、编译生成Go、Java代码
使用调用thrift
编译echo.thrift
文件。
#编译命令
thrift -r --gen go echo.thrift
thrift -r --gen java echo.thrift
编译后生成的Go源文件目录如下,需要重点关注一下echo.go
文件。
编译后生成的Java源文件目录如下。
4、用Go开发服务端
在echo.go
文件中可以发现Echo
接口和EchoHello
方法,如下图所示。服务器端要实现这个接口。
在 echoHandler.go
中实现了Echo
接口,EchoHello
方法如下代码块。
//echoHandler.go
type EchoHandler struct {
}
func (echo *EchoHandler) EchoHello(ctx context.Context, name string) (r string, err error) {
fmt.Println(name, " access")
return "hello," + name, nil
}
func NewEchoHandler() *EchoHandler {
return &EchoHandler{}
}
启动服务端。
//server.go
func main() {
transport, _ := thrift.NewTServerSocket("localhost:9090")
handler := NewEchoHandler()
processor := echo.NewEchoProcessor(handler)
server := thrift.NewTSimpleServer2(processor, transport)
_ = server.Serve()
}
5、用Java开发客户端
客户端的操作比较简单。
新建EchoClient.java
,配置transport和protocol,就可以调用服务端的服务了,实现如下:
public class EchoClient {
public static void main(String[] args) throws TException {
TSocket transport = new TSocket("localhost", 9090);
transport.open();
TProtocol protocol = new TBinaryProtocol(transport);
Echo.Client client = new Echo.Client(protocol);
String resp = client.echoHello("fly"); //RPC调用服务端的方法
System.out.println(resp);
transport.close();
}
}
运行该程序,远程调用服务器端的echoHello
方法,服务器端会返回处理结果,如下图所示。
到这里,就已经完成了一个简单的跨语言RPC调用啦。
6、原理简析
如果让你去实现一个RPC框架你会怎么去实现呢?
在没有接触Thrift之前,我有基于Zookeeper,Netty实现过一个简单的RPC调用,Zookeeper起到服务注册与服务发现的作用,Netty负责网络传输。客户端的调用会带上参数封装在自定义的协议里边,把协议通过FastJson序列化之后,通过Netty传输给服务端,服务端处理完成之后再类似地把结果传回给客户端。
其实,Thrift简单的原理也是这样的一个过程。Thrift 包含四个主要的组件:Transport,Protocol,Processor和Server。
+-------------------------------------------+
| Server |
| (single-threaded, event-driven etc) |
+-------------------------------------------+
| Processor |
| (compiler generated) |
+-------------------------------------------+
| Protocol |
| (JSON, compact etc) |
+-------------------------------------------+
| Transport |
| (raw TCP, HTTP etc) |
+-------------------------------------------+
Transport层用于服务端与客户端之间的通信。例子中用到的TSocket,TServerSocket
,是阻塞型 socket。
Protocol 定义了消息的序列化方式。一般来讲,作为RPC框架,考虑到网络传输的效率,使用二进制的传输协议,这也是thrift默认的传输协议。
Processor负责从输入流中获取请求,将结果写入到输出流中。
Server负责将上述所有功能组合在一起。
7、疑问
写到这里,突然产生了一个疑问,既然有Http请求为什么还要有RPC呢,该怎么去选择使用呢?欢迎小伙伴评论喔。