Thrift是一种支持多语言的软件框架,在各个服务之间的RPC通信领域应用非常广泛。RPC(远程过程调用)是一个计算机通信协议,该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。(参考远程过程调用)。

Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。

一、核心组件和特点

Thrift的核心组件有:

  1. TProtocol 协议和编解码组件
  2. TTransport 传输组件
  3. TProcessor 服务调用组件
  4. TServer,Client 服务器和客户端组件
  5. IDL 服务描述组件,负责生产跨平台客户端

作为一个高性能的RPC框架,Thrift的主要特点有:

  1. 基于二进制的高性能的编解码框架
  2. 基于NIO的底层通信
  3. 相对简单的服务调用模型
  4. 使用IDL支持跨平台调用

二、Thrift Type

Thrift Type包含了基本类型,自定义的结构体,容器,异常等,以下内容主要来自https://matt33.com/2016/04/07/thrift-learn/

2.1 基本类型(Base Types)
  • bool: 布尔变量(A boolean value, one byte);
  • byte: 8位有符号整数(A signed byte);
  • i16: 16位有符号整数(A 16-bit signed integer);
  • i32: 32位有符号整数(A 32-bit signed integer);
  • i64: 64位有符号整数(A 64-bit signed integer);
  • double: 64位浮点数(A 64-bit floating point number);
  • binary: byte数组(A byte array);
  • string: 字符串(Encoding agnostic text or binary string);
2.2 容器类型(Containers)
  • list: 一系列由T类型的数据组成的有序列表,元素可以重复;
  • set: 一系列由T类型的数据组成的无序集合,元素不可重复
  • map: 一个字典结构,key为T1类型,value为T2类型;
2.3 结构体(Struct)

结构体中包含一系列的强类型域,等同于无继承的class。可以看出struct写法很类似C语言的结构体。

struct Example {
  1:i32 number=10,
  2:i64 bigNumber,
  3:list<double> decimals,
  4:string name="thrifty"
}
2.4 可选与必选

Thrift提供两个关键字required,optional,分别用于表示对应的字段时必填的还是可选的。例如:

struct People {
    1: required string name;
    2: optional i32 age;
}

表示name是必填的,age是可选的。

2.5 联合(Union)

在一个结构体中,如果field之间的关系是互斥的,即只能有一个field被使用被赋值。在这种情况下,我们可以使用union来声明这个结构体,而不是一堆堆optional的field,语意上也更明确了。例如:

union JavaObjectArg {
  1: i32 int_arg;
  2: i64 long_arg;
  3: string string_arg;
  4: bool bool_arg;
  5: binary binary_arg;
  6: double double_arg;
}

三、RPC 调用分以下两种:

  • 同步调用:客户方等待调用执行完成并返回结果。
  • 异步调用:客户方调用后不用等待执行结果返回,但依然可以通过回调通知等方式获取返回结果。若客户方不关心调用返回结果,则变成单向异步调用,单向调用不用返回结果。

四、Thrift模型

thrift架构图 thrift原理和应用_thrift


如上图架构中各个层级,我们看其中的两个

4.1 协议层(传输格式)
  • TBinaryProtocol: 二进制格式;
  • TCompactProtocol:高效率的、密集的二进制编码格式进行数据传输;
  • TJSONProtocol:JSON格式;
  • TSimpleJSONProtocol:提供JSON只写协议, 生成的文件很容易通过脚本语言解析;
  • TDebugProtocol:使用易懂的可读的文本格式,以便于debug。
4.2 传输层(数据传输方式)
  • TSocket:阻塞式socker;
  • TFramedTransport:使用非阻塞方式,以frame为单位进行传输。
  • TFileTransport:以文件形式进行传输。
  • TMemoryTransport:将内存用于I/O. java实现时内部实际使用了简单的ByteArrayOutputStream。
  • TZlibTransport:使用zlib进行压缩, 与其他传输方式联合使用。当前无java实现。
  • TNonblockingTransport —— 使用非阻塞方式,用于构建异步客户端
4.3 服务模型
  • TSimpleServer:单线程服务器端使用标准的阻塞式 I/O,简单的单线程服务模型,常用于测试;
  • TThreadPoolServer:多线程服务模型,使用标准的阻塞式IO;
  • TNonblockingServer:多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式)。
4.4 Thrift RPC过程:

Client端通过Client Stub将接口、方法、参数按照协议规定的进行编码,并且通过网络传输到Server端。Server端的收到请求后交给Server Stub进行解码并发起后端调用,最终将执行结果返回Client

更详细的过程:
  (1). client代码像普通函数调用一样调用client stub函数,这个调用是本地调用,调用参数会和平常函数调用一样进行返回地址和调用参数压栈操作;
  (2). client stub会把调用参数和其它信息(比如调用方法名、调用属性等,可以称为metadata)进行打包封装成message,然后通过系统调用发送该message,这个打包的过程是个序列化的过程;
  (3). client寻求到服务端的地址,然后通过本地操作系统经由某种协议,将上述message发送给server端;
  (4). server端的操作系统接收message后将其传递给server stub;
  (5). server stub将message解包,得到原始传递过来的各项调用参数,解包的过程是反序列化的过程;
  (6). server stub调用server端的本地函数,然后将得到的结果按照上述类似的步骤反向传递给client作为结果返回。当然整个过程也可能不那么顺利,那么也应该产生合适的状态码、异常信息作为返回。
 所以RPC实际是通过client stub和server stub起到一个代理的作用,将client的请求转发到server端去操作,并将操作得到的结果回传,因为传递是跨进程、跨主机的,所以必须进行序列化和反序列化的过程来保证消息的正确性。关于stub的概念:https://www.jianshu.com/p/9ccdea882688

4.5 影响RPC性能点有哪些
  • 传输协议:HTTP、TCP、UDP
  • 序列化方案:Java自带的序列化、其他序列化框架Protobuf、Kryo、Hession
  • 工作模式:同步or异步

五、安装使用

关于安装过程可以参考 和https://matt33.com/2016/04/07/thrift-learn/这两篇文章

编写一个thrift文件,定义服务端的接口定义个服务接口

namespace java com.momo.learn.learn.thrift

struct Param{
	1: required i32 id;
	2: required string name;
    3: optional i32 age;
}

service HelloThriftService {
 i32 hello(1:string param1, 2:Param param2, 3:map<string,string> param3);
}

执行下边命令

thrift —gen java HelloThriftService.thrift

会看到下边这个图,相当于定义了接口的签名,服务端和客户端分别实现和引用接口就可以完成使用

thrift架构图 thrift原理和应用_RPC_02


参考文章:

http://thrift.apache.org/

https://matt33.com/2016/04/07/thrift-learn/

重点推荐:https://www.kancloud.cn/digest/thrift/118986