这题目一看就是老标题党啦。既然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文件放在任意文件夹就好了。

thrift01.png

可以把当前文件夹添加进path环境变量,方便使用。

path.png

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 文件。

gen-go.png

编译后生成的Java源文件目录如下。

gen-java.png

4、用Go开发服务端

echo.go 文件中可以发现Echo接口和EchoHello方法,如下图所示。服务器端要实现这个接口。

server.png

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方法,服务器端会返回处理结果,如下图所示。

结果.png

到这里,就已经完成了一个简单的跨语言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呢,该怎么去选择使用呢?欢迎小伙伴评论喔。

参考

1、http://thrift.apache.org/tutorial/

2、使用Thrift框架实现C#调用Java服务

文章来源于互联网:【原创】快速实践跨语言RPC框架- Apache Thrift

发表评论