目前流行的服务调用方式有很多种,例如基于 SOAP 消息格式的 Web Service,基于 JSON 消息格式的 RESTful 服务等。其中所用到的数据传输方式包括 XML,JSON 等,然而 XML 相对体积太大,传输效率低,JSON 体积较小,新颖,但还不够完善。本文将介绍由 Facebook 开发的远程服务调用框架 Apache Thrift,它采用接口描述语言定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以在多种语言中,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等创建高效的、无缝的服务,其传输数据采用二进制格式,相对 XML 和 JSON 体积更小,对于高并发、大数据量和多语言的环境更有优势。本文将详细介绍 Thrift 的使用,并且提供丰富的实例代码加以解释说明,帮助使用者快速构建服务
-----------------------------------分割线----------------------------------------------------------------
1.下载thrift,我们这里下载最新的0.9.0的windows版本。
2. 进入thrift的目录,定义服务描述文件,thrift的服务描述文件以thrift结尾,类似于web services的wsdl文件。thrift提供了丰富的数据接口用于不同语言之间的服务需求。其数据结构如下
Base Types:基本类型
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:结构体类型
Container:容器类型,即List、Set、Map
Exception:异常类型
Service: 定义对象的接口,和一系列方法
我们测试定义个叫做Test的服务,其右一个ping方法用户传输一个int32类型的数据。其thrift文件描述如下
namespace java net.johnc.thrift service Test{ void ping(1: i32 length) }
可以看到定义了一个叫做Test的服务,并定义了相关方法,其中1:用户标识参数的编号。
3. 进入thrift的目录,运行$ thrift -r --gen java test.thrift // -r对其中include的文件也生成服务代码 -gen是生成服务代码的语言,此时进入$gen-java的目录下就可以看到生成对应的java文件,该文件即是相应服务端和客户端的实现【其实此处也类似于web services中通过wsdl生成相应代码的情况】。
4.编写客户端
TTransport transport;
try {
transport = new TSocket("localhost", 1234);
TProtocol protocol = new TBinaryProtocol(transport);
Test.Client client = new Test.Client(protocol);
transport.open();
client.ping(2012);
transport.close();
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
如上所示:客户端像服务端调用ping方法,发送2012这个数值
5.编写服务端
服务实现类TestImpl
public class TestImpl implements Test.Iface{
public void ping(int length) throws TException {
System.out.println("client length:"+length);
}
}
服务启动类Server
public class Server {
public void startServer() {
try {
TServerSocket serverTransport = new TServerSocket(1234);
Test.Processor process = new Processor(new TestImpl());
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) {
Server server = new Server();
server.startServer();
}
}
6.分别启动服务端和客户端,即可实现客户端向服务端发送int数值的效果
从例子中可以看出,thrift的工作流程
FooServeice:是由服务描述文件.thrift 生成而来,不同的语言可以生成不同版本,thrift目前已经支持C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk等语言(本例中都是以java为例子)
Foo.read()/writer():在服务的下一层提供基础的读写方法,客户端可以向服务端写数据,也可以从服务端接收数据,服务端可以向客户端写数据,也可以向客户端读取数据。
Foo.read()/writer():在服务的下一层提供基础的读写方法,客户端可以向服务端写数据,也可以从服务端接收数据,服务端可以向客户端写数据,也可以向客户端读取数据。
TProcotol:传输协议层,thrift提供了丰富的传输协议,主要包含如下:
TBinaryProtocol – 二进制编码格式进行数据传输。
TCompactProtocol – 这种协议非常有效的,使用Variable-Length Quantity (VLQ) 编码对数据进行压缩。
TJSONProtocol – 使用JSON的数据编码协议进行数据传输。
TSimpleJSONProtocol – 这种节约只提供JSON只写的协议,适用于通过脚本语言解析
TDebugProtocol – 在开发的过程中帮助开发人员调试用的,以文本的形式展现方便阅读。
TTransport:
TSocket- 使用堵塞式I/O进行传输,也是最常见的模式。
TFramedTransport- 使用非阻塞方式,按块的大小,进行传输,类似于Java中的NIO。
TFileTransport- 顾名思义按照文件的方式进程传输,虽然这种方式不提供Java的实现,但是实现起来非常简单。
TMemoryTransport- 使用内存I/O,就好比Java中的ByteArrayOutputStream实现。
TZlibTransport- 使用执行zlib压缩,不提供Java的实现。
服务端在处理客户端请求上也提供多种的模式,包括如下
TSimpleServer:单线程阻塞方式
TThreadPoolServer:多线程阻塞方式
TNonblockingServer:非阻塞的方式以块传输数据
--------------------------------------------------分割线-------------------------------------------------------------
性能测试
协议传输量对比
协议耗费资源对比