Thrift简介及安装

【thrift是什么】

thrift的全名叫做Apache thrift,是一款软件开发RPC框架,可以很高效地实现跨语言的RPC服务。

如果你还不了解RPC是什么,赶快看看这里

如果想参观参观thrift的官方网站,请点击这里

【thrift生于何地】

thrift最初生于Facebook,并茁壮成长,在2007年由Facebook正式开源出来,2008年由Apache软件基金会开始负责项目孵化直至今日。

【还有哪些RPC框架】

protobuf、Avro、MessagePack等,如果你有兴趣,可以搜索一下他们,也有利于你更好的了解RPC这个领域的发展情况。

【下载thrift】

目前的最新版本是thrift-0.9.1

【安装thrift】

首先建议你安装如下这些软件包:

automake libtool flex bison pkgconfig gcc-c++ boost-devel 
libevent-devel zlib-devel python-devel ruby-devel

然后从官网下载thrift源码包,并进行编译链接:

./configure –-prefix=/your/program/path/ --enable-libtool-lock
make
make install

安装完成后,你会看到thrift其实包含了三部分:一个bin程序、一坨头文件和若干库文件

【为什么需要thrift】

如果你之前没有接触过RPC框架的话,可能理解起来会比较困难。为了照顾这些新用户的感受,我尝试着用一种好理解的思路来解释:

研发工程师小吴接到了一个新任务,给“托福考试成绩数据库”增加一个“成绩查询”的功能,客户端提供“用户ID”向服务器端发起查询请求,服务器端接到查询请求后从数据库中取回此用户ID对应的姓名和成绩,并返回给客户端。

就是这样一个简单的Client-Server通信过程,其实就形成了一个典型的RPC场景。服务器端提供“成绩查询服务”,客户端会通过约定的方法来查询成绩。

小吴设计的方法调用和数据传输是这样的:

thrift example

 

通过上图可以看到,服务器端处于监听状态(等待请求的到来),客户端发起一个名为Search的动作,参数是用户ID,而这个动作的返回是一个结构体struct UserGradeInfo,其中包含了用户的名字(UserName)和用户的成绩(UserGrade)。

设计做完了,小吴要开始编码了。如果按照“手工作坊”的思路,小吴至少需要完成如下几个方面:

(1)“客户端向服务器端发送数据”的代码

(2)“客户端接收服务器端查询结果”的代码

(3)“服务器端接收客户端数据”的代码

(4)“服务器端向客户端发送查询结果”的代码

(5)如果客户端会大批量发起查询,那可能还需要考虑改成多线程模型或异步模型

(6)而且还有可能因为某种原因,要求客户端和服务器端使用不同的语言进行开发

照此思路,小吴至少要3周时间来开发和自测。(时间很长,对吧)

但,自从thrift出现后(更准确的说,是自从RPC开发框架出现后),上述工作量被大大简化了。我们只要调用一个thrift工具就可以自动生成上述的所有代码,即便服务器端和客户端使用不同的语言,thrift也照样支持。

至此,我相信你应该大概理解thrift能帮我们做什么了吧。

【thrift到底怎么用】

依然拿上面的“成绩数据库”的例子来说,thrift的使用可以被分为四步:

第1步: 明确要交互的数据格式(如上例中的UserGradeInfo)和具体的方法(如上例中的Search),定义出thrift接口描述文件(英文叫做Inteface Description File);

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

第3步: 你的服务器端程序引用thrift生成的RPC代码,并实现其中的Search动作的逻辑,然后启动监听,等待客户端发来请求。

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

(如果你觉得这样描述太空虚,别急,稍后会有完整的例子)

【thrift接口描述文件怎么编写】

如果你是学院派,那么我推荐你研究thrift IDL(Interface Definition Language)规范,在这里。虽然有些晦涩,但你可以从中了解到一个接口文件可以如何来写。

在编写接口文件时,需要对你要传输的数据设定数据类型,比如UserName是字符串型,UserGrade是整型等。因为thrift是支持众多开发语言的,所以thrift提供了一套自己的数据类型编写规范,只有用这套独立于任何语言的类型规范来编写接口文件,thrift才能把它转换成你指定的那种开发语言的代码。

thrift中的类型包括基础类型、结构、容器、异常、服务等几个部分。(官网中有专门介绍数据类型的页面,在这里)

【类型 之 基础类型】

基础类型,其实非常简单和明确:

(1)bool:布尔类型(true或false)

(2)byte:8位有符号整数

(3)i16:16位有符号整数

(4)i32:32位有符号整数

(5)i64:64位有符号整数

(6)double:64位浮点数

(7)string:文本字符串,使用UTF-8编码

(有些细心的同学会询问“为什么不支持无符号整数类型呢?”,这是因为在很多开发语言中并没有原生的无符号整型。)

【类型 之 容器】

thrift容器包括了各种语言中最常用的容器,共三种:

(1)list容器:一个元素可重复的有序列表。会被转换成C++中的vector,Java中的ArrayList,脚本语言中的数组等。

(2)set容器:一个元素不可重复的无序集合。会转换成C++中的set,Java中的HashSet、Python中的Set等。(熟悉PHP的同学可能会问“PHP并不支持set类型,怎么办”,在PHP语言中,thrift会将set容器转换成List。)

(3)map容器:一个含有多个key:value键值对的结构。会被转换成C++中的map,Java中的HashMap,PHP中的关联数组,Python/Ruby中的dictionary等。

对于上述三种容器,其元素的类型原则上可以是任何一种thrift类型。但是值得注意的是,map的key类型需要是基础类型,因为很多开发语言并不支持map的key类型为复杂数据类型。

【类型 之 结构体】

结构体类型,在形式上和C/C++中的结构体类型非常相似,就是一坨类型的组合,比如上文图中的UserGradeInfo便是一个thrift结构体类型。

thrift接口文件中的结构体类型,都会被转换成一个独立的类(Class)。类的属性便是结构体中的各个类型,而类的方法便是对这些类型进行处理的相关函数。

我们来看一个结构体定义的例子:

 

 

?

1

2

3

4

5

6

7

8

9

 

 

struct UserGradeInfo {

1: required string UserName = "Anonymous";

2: required i16 UserGrade = 0;

}

 

 可以看到,结构体中每一个域都有一个正整数标识符,这个标识符并不要求连续,但一旦定义,不建议再进行修改。

另外,每个域前都会有required或optional的限定,前者表示是必填域,后者则表示是可选域。域是可以有默认值的,比如上例中的“Anonymous”和0。

(1)如果一个域设置了required,但是在实际构造结构体时又没有给这个域赋值,那么thrift会认为这是一个异常。

(2)如果一个域设置为optional且在构造结构体时没有给这个域赋值,那么在使用这个结构体时,就会忽略掉这个optional的域。

【类型 之 异常】

除了使用exception来替代struct以外,“异常”这个类型,在语法上和刚才介绍过的结构体的用法是完全一致的。但是从语义上讲,exception和struct却大相径庭。exception是在远程调用发生异常时用来抛出异常用的。

【类型 之 服务】

服务的定义,与面向对象技术中定义一个接口很类似,而这些接口其实就是纯虚函数。thrift编译工具会根据服务的定义来产生相应的方法和函数。

每个服务,都包括了若干个函数,每个函数包括了若干参数和一个返回值(返回值可以是void)。

(小技巧:返回值为void的函数,你可以在函数名前加上oneway标识符,将此函数以异步模式执行,这样在调用此函数后,函数会立即返回。)

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

你可能感兴趣的:(thrift安装,thrift学习)