简介
thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈代码生成引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务 。
thrift最初由facebook开发,07年四月开放源码,08年5月进入apache孵化器。 thrift 允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。看到这里,感觉thrift的作用与webservice差不多,webservice使用xml文件传输,文件太大,效率不高,thrift使用二进制数据,效率更高!
Thrift 主要由5个部分组成:
-
类型系统以及 IDL(interface definition language) 编译器:负责由用户给定的 IDL 文件生成相应语言的接口代码
-
TProtocol:实现 RPC 的协议层,可以选择多种不同的对象串行化方式,如 JSON, Binary。
-
TTransport:实现 RPC 的传输层,同样可以选择不同的传输层实现,如socket, 非阻塞的 socket, MemoryBuffer 等。
-
TProcessor:作为协议层和用户提供的服务实现之间的纽带,负责调用服务实现的接口。
-
TServer:聚合 TProtocol, TTransport 和 TProcessor 几个对象。
上述的这5个部件都是在 Thrift 的源代码中通过为不同语言提供库来实现的,这些库的代码在 Thrift 源码目录的 lib 目录下面,在使用 Thrift 之前需要先熟悉与自己的语言对应的库提供的接口。
下图描绘了Thrift的整体架构,分为6个部分:
1.你的业务逻辑实现(You Code)
2.客户端和服务端对应的Service
3.执行读写操作的计算结果
4.TProtocol
5.TTransports
6.底层I/O通信
图 中前面3个部分是:
1、你通过Thrift脚本文件生成的代码
2、图中的褐色框部分是你根据生成代码构建的客户端和处理器的代码
3、图中红色的部分是两端产生的计算结果
从TProtocol下面3个部分是Thrift的传输体系和传输协议以及底层I/O通信,Thrift并且提供 堵塞、非阻塞,单线程、多线程的模式运行在服务器上,还可以配合服务器/容器一起运行,可以和现有JEE服务器/Web容器无缝的结合。
服务端和客户端具体的调用流程如下:
该图所示是 HelloServiceServer 启动的过程以及服务被客户端调用时,服务器的响应过程。从图中我们可以看到,程序调用了 TThreadPoolServer 的 serve 方法后,server 进入阻塞监听状态,其阻塞在 TServerSocket 的 accept 方法上。当接收到来自客户端的消息后,服务器发起一个新线程处理这个消息请求,原线程再次进入阻塞状态。在新线程中,服务器通过 TBinaryProtocol 协议读取消息内容,调用 HelloServiceImpl 的 helloVoid 方法,并将结果写入 helloVoid_result 中传回客户端。
该图所示是 HelloServiceClient 调用服务的过程以及接收到服务器端的返回值后处理结果的过程。从图中我们可以看到,程序调用了 Hello.Client 的 helloVoid 方法,在 helloVoid 方法中,通过 send_helloVoid 方法发送对服务的调用请求,通过 recv_helloVoid 方法接收服务处理请求后返回的结果。
数据类型
Thrift 脚本可定义的数据类型包括以下几种类型:
基本类型:
bool:布尔值,true 或 false,对应 Java 的 boolean
byte:8 位有符号整数,对应 Java 的 byte
i16:16 位有符号整数,对应 Java 的 short
i32:32 位有符号整数,对应 Java 的 int
i64:64 位有符号整数,对应 Java 的 long
double:64 位浮点数,对应 Java 的 double
string:未知编码文本或二进制字符串,对应 Java 的 String
结构体类型:
struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
容器类型:
list:对应 Java 的 ArrayList
set:对应 Java 的 HashSet
map:对应 Java 的 HashMap
异常类型:
exception:对应 Java 的 Exception
服务类型:service:对应服务的类
协议
Thrift可以让你选择客户端与服务端之间传输通信协议的类别,在传输协议上总体上划分为文本(text)和二进制(binary)传输协议, 为节约带宽,提供传输效率,一般情况下使用二进制类型的传输协议为多数,但有时会还是会使用基于文本类型的协议,这需要根据项目/产品中的实际需求:
* TBinaryProtocol – 二进制编码格式进行数据传输。
Factory proFactory = new TBinaryProtocol.Factory();
* TCompactProtocol – 高效率的、密集的二进制编码格式进行数据传输
TCompactProtocol.Factory proFactory = new TCompactProtocol.Factory();
* TJSONProtocol – 使用JSON的数据编码协议进行数据传输。
TJSONProtocol.Factory proFactory = new TJSONProtocol.Factory();
* TSimpleJSONProtocol – 只提供JSON只写的协议,适用于通过脚本语言解析
* TDebugProtocol – 在开发的过程中帮助开发人员调试用的,以文本的形式展现方便阅读
传输层
* TSocket- 使用阻塞式I/O进行传输,也是最常见的模式。
* TFramedTransport- 使用非阻塞方式,按块的大小,进行传输,类似于Java中的NIO。
* TFileTransport- 顾名思义按照文件的方式进程传输,虽然这种方式不提供Java的实现,但是实现起来非常简单。
* TMemoryTransport- 使用内存I/O,就好比Java中的ByteArrayOutputStream实现。
* TZlibTransport- 使用执行zlib压缩,不提供Java的实现。
服务端类型
* TSimpleServer - 单线程服务器端使用标准的阻塞式I/O。
* TThreadPoolServer - 多线程服务器端使用标准的阻塞式I/O。
* TNonblockingServer - 多线程服务器端使用非阻塞式I/O,并且实现了Java中的NIO通道。
下载thrift
现在windows版本进行测试,目前最新的版本地址:http://apache.fayea.com/thrift/0.9.3/thrift-0.9.3.exe。
编写thrift
namespace java com.demo.thrift
service HelloService{
void helloVoid(1: string arg)
}
thrift-0.9.3.exe -r -gen java hello_service.thrift
执行命令生成java代码文件夹
生成一个HelloService.java文件,内容太多就不贴代码了。
编写一个HelloServiceImpl实现HelloService.Iface里面接口
package com.demo.thrift;
public class HelloServiceImpl implements HelloService.Iface {
public void helloVoid(String arg) throws org.apache.thrift.TException{
System.out.println("hello " + arg);
}
}
server代码:
package com.demo.thrift;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TBinaryProtocol.Factory;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.server.TThreadPoolServer.Args;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
public class HelloServiceServer {
public void startServer() {
try {
TServerSocket serverTransport = new TServerSocket(1234);
HelloService.Processor process = new HelloService.Processor(new HelloServiceImpl());
Factory portFactory = new TBinaryProtocol.Factory(true, true);
Args args = new Args(serverTransport);
args.processor(process);
args.protocolFactory(portFactory);
TServer server = new TThreadPoolServer(args);
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
HelloServiceServer server = new HelloServiceServer();
server.startServer();
}
}
client代码:
package com.demo.thrift;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
public class HelloServiceClient {
public void startClient() {
TTransport transport;
try {
transport = new TSocket("localhost", 1234);
TProtocol protocol = new TBinaryProtocol(transport);
HelloService.Client client = new HelloService.Client(protocol);
transport.open();
client.helloVoid("world");
transport.close();
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
HelloServiceClient client = new HelloServiceClient();
client.startClient();
}
}