学习-Thrift

来源:互联网 发布:全看网软件下载 编辑:程序博客网 时间:2024/06/07 17:24

本文先整体性地介绍Thrift框架,然后分析Thrift源码中自带的toturial例子,作为Thrift的入门吧。

一.Thrift介绍

Thrfit是一种开源的跨语言的服务部署框架,这里的服务是指RPC,即远程过程调用了。它最初是由Facebook开发的,后来Facebook将其开源了。

因此你可以很方便地下载到它的源代码,下载地址为:http://incubator.apache.org/thrift/download/

 

Thrift的体系架构如下:


实际上Thrift提供了一个支持多语言的Lib库,包括C++、Java、PHP、Python、Ruby等。同时它自定义了一种中间语言(Thrift IDL),

用于编写统一格式的thrift配置文件,定义数据类型。然后根据此配置文件调用lib库中的生成器来生成指定语言的服务,这正体现其跨语言的特性。

 

Thrift支持五种数据类型:
Base Types:基本类型
Struct:结构体类型
Container:容器类型,即List、Set、Map
Exception:异常类型
Service:类似于面向对象的接口定义,里面包含一系列的方法

下面是Thrift中所支持的类型(前三种类型)

 

Thrift通过两种抽象机制来完成底层客户端和服务器端的通信,分别是:

1)  Transport:抽象了底层网络通信部分的接口
TTransport对Java I/O层进行封装,抽象了底层网络通信部分的接口。主要是对以下6种接口进行了抽象:open, close, isopen, read, write, flush。

2)  Protocol:抽象了对象在网络中传输部分的接口,它规定了thrift的RPC可以调用的接口。这些接口是为了传输不同类型的数据而设计的。

   Transport在传输数据时是不区分所传的数据类型的,一律以流的形式传输。所以Protocol类在Transport类之上实现了按数据类型来传输数据。

Transport的类结构实现:

socket的封装

 

TTransport是一个抽象的基类,对socket进行了封装,提供了对流的一系列操作接口。thrift提供了两种常用类型的Socket,一种是阻塞式的,两外一种是非阻塞式的。

这两种socket的区别实际上就是传统IO和NIO的区别,这里就不累述了。通过close()和open()来建立和关闭连接;通过read()和write()来对流进行读写。

 

ServerSocket的封装

 

TServerSocket同样是一个抽象的基类,对ServerSocket进行了封装。它是以非阻塞的IO方式进行通讯的。通过listen()来监听连接请求,通过accept()来获取。

 

Protocol的类结构实现:

 

TProtocol提供了一系列按类型进行读写的接口。并持有一个TTransport对象的引用,所以TProtocol类是依赖于TTransport类的。

其中定义了一系列的write和read方法,应该说每种类型对应一套write和read方法。在write和read方法中会分别调用TTransport

中的write和read方法进行实际的读写操作。

 

RPC的具体实现:

1. TProcessor

它是thrift中最简单的一个接口了,仅包含一个方法:
bool process(TProtocol in, TProtocol out)throws TException

此方法有两个参数in和out,分别用于从socket中读取数据和向scoket中写数据。每个service对象中都会包含一个实现了此接口的类对象(Process),

这个类就是处理RPC请求的核心。

 

2. TServer

TServer相当于一个容器,拥有生产TProcessor、TTransport、TProtocol的工厂对象。它的工作流如下:

1) 使用TServerTransport来获取一个TTransport(客户端的连接)

2) 使用TTransportFactory来将获取到的原始的transport转化为特定的transport

3) 使用TProtocolFactory来为获取TTransport的输入输出,即TProtocol

4) 唤醒TProcessor的process方法,处理请求并返回结果

 

 

 

二. tutorial 分析

现在结合一个例子来研究如何应用Thrift。例子就是thrift源代码中自带的tutorial,测试语言方面则选择java。

在此之前,必须安装好Thrift,安装过程就不累述了,可以参考thrift中的readme文件。

 

1.我们可以使用Ant工具将thrift的java lib打包成jar文件,这样可以直接导入Eclipse使用。

进入到tutorial根目录,里面有两个文件.thrift,这就是上面讲到的配置文件了,里面定义了我们要提供的服务。下面是其中的一个文件的内容:

 

+ expand sourceview plaincopy to clipboardprint?

 

2.输入如下命令生成代码:thrift -r --gen java tutorial.thrift

完成后,会发现多了一个gen-java的文件夹,这就是生成的代码。我们看下代码结构:

     

两个service类(ShareService和Calculator)均包含两个内部类:Client和Processor,前者用于客户端,后者用于服务器端。

这两个类均包含一套service方法的实现(ping、add、calculate、zip),RPC就是基于这套共用方法实现的。

3.经过上面的两步,我们得到了两个jar文件,libthrift.jar和tutorial.jar,至此环境已经部署完成。分别运行JavaServer和JavaClient,开启服务器端

和客户端,观察运行结果。

JavaServer.java

 

+ expand sourceview plaincopy to clipboardprint?

 

JavaClient.java

 

+ expand sourceview plaincopy to clipboardprint?

 

 ping()的序列图:

 

4.当然,我们可以使用不同语言的客户端和服务器端。

  例如:我们可以将客户端换成php语言的。
  1)进入到tutorial根目录,执行如下命令:thrift --gen php shared.thrift    thrift --gen php tutorial.thrift

    完成后会发现多了一个gen-php目录。

  2)启动java服务器端,方法同上。

  3)启动php客户端,观察测试结果。

  PS:我的服务器端运行在Windows系统中,直接将生成的libthrift.jar和tutorial.jar导入到Eclipse中,然后运行JavaServer文件即可。

  而客户端呢我是运行在虚拟机的Ubuntu系统中,启动客户端前需安装php(apt-get install php5)。同时,修改PhpClient.php中的ip为宿主机的ip。最后,输入如下命令启动:php PhpClient.php。

  通过输出显示,客户端和服务器端的语言不影响执行的结果,这正是thrift的跨语言性。

 

4、 Thrift安装

下载:http://incubator.apache.org/thrift/download/

安装要求:

Unix/linux 系统,windows+cygwin

C++语言:g++、boost

java 语言:JDK、Apache Ant

其他语言:Python、PHP、Perl, etc…

编译安装:./configure –》make –》make install

1、 利用Thrift部署服务

主要流程:编写服务说明,保存到.thrift文件–》根据需要, 编译.thrift文件,生成相应的语言源代码–》根据实际需要, 编写client端和server端代码。

(1).thrift文件编写

一般将服务放到一个.thrift文件中,服务的编写语法与C语言语法基本一致,在.thrift文件中有主要有以下几个内容:变量声明、数据声明(struct)和服务接口声明(service, 可以继承其他接口)。

下面分析Thrift的tutorial中带的例子tutorial.thrift

包含头文件:

59行:include “shared.thrift”

指定目标语言:

65行:namespace cpp tutorial

定义变量:

80行:const i32 INT32CONSTANT = 9853

定义结构体:

103行:struct Work {

1: i32 num1 = 0,

2: i32 num2,

3: Operation op,

4: optional string comment,

}

定义服务:

service Calculator extends shared.SharedService {

void ping(),

i32 add(1:i32 num1, 2:i32 num2),

i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),

oneway void zip()

}

     要生成C++代码:./thrift --gen cpp tutorial.thrift,结果代码存放在gen-cpp目录下
     要生成java代码:./thrift --gen java tutorial.thrift,结果代码存放在gen-java目录下      ….. 

(2) client端和server端代码编写

client端和sever端代码要调用编译.thrift生成的中间文件。

下面分析cpp文件下面的CppClient.cpp和CppServer.cpp代码

在client端,用户自定义CalculatorClient类型的对象(用户在.thrift文件中声明的服务名称是Calculator, 则生成的中间代码中的主类为CalculatorClient), 该对象中封装了各种服务,可以直接调用(如client.ping()), 然后thrift会通过封装的rpc调用server端同名的函数。

在server端,需要实现在.thrift文件中声明的服务中的所有功能,以便处理client发过来的请求。

【参考资料】
1、 http://wiki.apache.org/thrift/
2、 http://jnb.ociweb.com/jnb/jnbJun2009.html
3、 http://blog.rushcj.com/tag/thrift/
4、 http://www.vvcha.cn/c.aspx?id=31984
5、http://www.thoss.org.cn/mediawiki/index.php/Thrift%E7%9A%84%E9%80%9A%E4%BF%A1%E6%9C%BA%E5%88%B6%E5%8F%8A%E5%85%B6%E5%9C%A8cassandra%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8

Reference:

http://incubator.apache.org/thrift/static/thrift-20070401.pdf

http://jnb.ociweb.com/jnb/jnbJun2009.html

http://pickerel.javaeye.com/blog/318734

http://www.vvcha.cn/c.aspx?id=31984

http://www.thoss.org.cn/mediawiki/index.php/Thrift%E7%9A%84%E9%80%9A%E4%BF%A1%E6%9C%BA%E5%88%

原创粉丝点击