简介

Thrift由Facebook研发,主要用于各个服务之间的RPC通信(与上篇博客:gRPC同类),支持跨语言,常用的语言比如C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml都支持。Thrift是一个典型的 CS(客户端/服务端) 结构,在服务器端实现代码,提供接口;客户端可以直接调用接口,客户端和服务端可以使用不同的语言开发。既然客户端和服务端能使用不同的语言开发,那么一定就要有一种中间语言来关联客户端和服务端的语言,没错,这种语言就是IDL(Interface Description Language)

安装

源码安装

# 下载安装包
curl -# -O http://archive.apache.org/dist/thrift/0.9.2/thrift-0.9.2.tar.gz
# 下载完成后开始解压
tar zxvf thrift-0.9.2.tar.gz
# 进入文件夹
cd thrift-0.9.2
# 初始化配置
./configure
# 开始构建
make
# 一定要用sudo,本机编译
sudo make install
# 查看thrift是否生效
thrift --version
# 显示:Thrift version 0.9.2 

macOS安装

brew install thrift

安装python thrift库

pip install thrift

使用流程

  1. 明确要交互的数据格式和具体的方法,定义出thrift接口描述文件,以thrift为后缀(英文叫做IntefaceDescription File)

  2. 调用thrift工具,依据thrift接口文件,生成RPC代码;

  3. 服务器端程序引用thrift生成的RPC代码,并实现thrift中定义的逻辑,然后启动监听,等待客户端发来请求。

  4. 客户端同样引入并调用RPC代码来与服务器端通信

Thrift基本语法

类型

Thrift类型系统包括预定义的基本类型,用户自定义结构体,容器类型,异常和服务定义。

基本类型(Basic types)
  • bool: 布尔类型,true或false,占1字节
  • byte: 有符号char
  • i16: 16位有符号整数
  • i32: 32位有符号整数
  • i64: 64位有符号整数
  • double: 64位浮点数
  • binary: 字符数组
  • string: 字符串(比如二进制字符串或者其他编码过的文本)
容器(Containers)
  • list: 一系列由T类型的数据组成的有序列表,元素可以重复。会被转换成C++中的vector,Java中的ArrayList,脚本语言中的数组等;
  • set: 一系列由T类型的数据组成的无序集合,元素不可重复。会转换成C++中的set,Java中的HashSet、Python中的Set等;
  • map: 一个字典结构,key为K类型,value为V类型,相当于Java中的HMap。一个含有多个key:value键值对的结构。会被转换成C++中的map,Java中的HashMap,PHP中的关联数组,Python/Ruby中的dictionary等
结构体类型(Structs)

Thrift结构体类型在概念上类似于C语言中结构体类型,Thrift结构体将会被转换成面向对象语言中的类。
```c++
struct People {
1: required string name;
2: required i32 age = 20;
3: optional string sex;
}

可以看到,结构体中每一个域都有一个正整数标识符,这个标识符并不要求连续,但一旦定义,不建议再进行修改
另外,每个域前都会有required或optional的限定,前者表示是必填域,后者则表示是可选域。域是可以有默认值的,比如上例中的“age"。
如果一个域设置为optional且在构造结构体时没有给这个域赋值,那么在使用这个结构体时,就会忽略掉这个optional的域

#### 异常(Exceptions)
异常在语法和功能上类似于结构体,一个差别是异常使用关键字exception而不是struct来声明。但他们在语义上有明显不同之处:当定义一个RPC服务时,我们可以声明一个远程方法能够抛出一个异常。
```c++
exception RequestException {
    1: i32 code;
    2: string reason;
}
服务(Services)

服务的定义,与面向对象技术中定义一个接口很类似,而这些接口其实就是纯虚函数。thrift编译工具会根据服务的定义来产生相应的方法和函数。
每个服务,都包括了若干个函数,每个函数包括了若干参数和一个返回值(返回值可以是void.
(小技巧:返回值为void的函数,你可以在函数名前加上oneway标识符,将此函数以异步模式执行,这样在调用此函数后,函数会立即返回。)

对于返回void的函数,thrift仍然会确保函数返回,这样就表示这个函数已被正确执行,且服务器端已有返回信息了。但是如果给void的函数前加上oneway,那么此函数的返回只能表示数据已经进入传输层,并不能表示服务器端已经收到并返回了数据

```c++
service vulgar_detect{
bool is_vulgar(1:string title),
i32 calc(1: i32 num)
}


##### 传输协议 

在传输协议上总体划分为文本和二进制 ,为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数.

* TBinaryProtocol — 二进制编码格式进行数据传输
* TCompactProtocol — 高效率的、密集的二进制编码格式进行数据传输
* TJSONProtocol — 使用 JSON 的数据编码协议进行数据传输
* TSimpleJSONProtocol — 只提供 JSON 只写的协议,适用于通过脚本语言解析
* TDebugProtocol – 使用易懂的可读的文本格式,以便于 debug
##### 数据传输

* TSocket — 使用阻塞式 I/O 进行传输,是最常见的模式
* TFramedTransport — 使用非阻塞方式,按块的大小进行传输
* TNonblockingTransport — 使用非阻塞方式,用于构建异步客户端
* TMemoryTransport – 将内存用于 I/O
* TZlibTransport – 使用 zlib 进行压缩, 与其他传输方式联合使用
* TFileTransport – 以文件形式进行传输
##### 服务端类型

* TSimpleServer — 单线程服务器端使用标准的阻塞式 I/O
* TThreadPoolServer —— 多线程服务器端使用标准的阻塞式 I/O
* TNonblockingServer —— 多线程服务器端使用非阻塞式 I/O

#### thrift编译工具
在我们编写好thrift接口描述文件之后,thrift编译工具就要派上用场了,它的作用就是根据thrift接口描述文件来生成相应开发语言的RPC代码.
在终端下输入:
```shell
thrift --gen ${开发语言} ${thrift接口描述文件}

关于thrift的更多命令可以输入:

thrift --help

实战演练

  1. 定义接口文件example.thrift

```c++
namespace py example

struct Data {
1: string text
2: i32 id
}

service format_data {
Data do_format(1:Data data),
}


2. 用thrift命令编译example.thrift文件生成python代码
```shell
thrift -out . --gen py example.thrift
# 参数说明:
    -out .:表示生成的代码在当前目录,并且命名不带gen-前缀,如果用-o参数是带有gen-前缀的

这一步生成的代码结构如下图:
<微服务架构>—Thrift篇_第1张图片

  1. 参考服务端客户端源代码Github,或者直接git clone

  2. 先启动服务端python server.py,再运行客户端python client.py,输入如下:
>>>client-requets
>>>server-answer Data(text='HELLO,WORLD!', id=123)
致辞,完结,欢迎大伙到github交流学习