Total Pageviews

Tuesday, 26 September 2017

跨语言服务部署框架Thrift

Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。
Thrift的系统架构
Thrift包含一个完整的堆栈结构用于构建客户端和服务器端。下图描绘了 Thrift 的整体架构。

如图所示,图中黄色部分是用户实现的业务逻辑,褐色部分是根据 Thrift 定义的服务接口描述文件生成的客户端和服务器端代码框架,红色部分是根据 Thrift 文件生成代码实现数据的读写操作。红色部分以下是 Thrift 的传输体系、协议以及底层 I/O 通信,使用 Thrift 可以很方便的定义一个服务并且选择不同的传输协议和传输层而不用重新生成代码。
Thrift实际上是实现了C/S模式,通过代码生成工具将接口定义文件生成服务器端和客户端代码(可以为不同语言),从而实现服务端和客户端跨语言的支持。用户在Thirft描述文件中声明自己的服务,这些服务经过编译后会生成相应语言的代码文件,然后用户实现服务(客户端调用服务,服务器端提服务)便可以了。其中protocol(协议层, 定义数据传输格式,可以为二进制或者XML等)和transport(传输层,定义数据传输方式,可以为TCP/IP传输,内存共享或者文件共享等)被用作运行时库。
Thrift代码产生方式
Thrift的网络栈如下所示:

  • Transport层提供了一个简单的网络读写抽象层。这使得thrift底层的transport从系统其它部分(如:序列化/反序列化)解耦。Transport接口提供的方法:open,close,read,write,flush。
  • Protocol抽象层定义了一种将内存中数据结构映射成可传输格式的机制。换句话说,Protocol定义了datatype怎样使用底层的Transport对自己进行编解码。因此,Protocol的实现要给出编码机制并负责对数据进行序列化。
  • Processor封装了从输入数据流中读数据和向数据数据流中写数据的操作。读写数据流用Protocol对象表示。Processor的结构体非常简单:与服务相关的processor实现由编译器产生。Processor主要工作流程如下:从连接中读取数据(使用输入protocol),将处理授权给handler(由用户实现),最后将结果写到连接上(使用输出protocol)。
  • Server将以上所有特性集成在一起:
    • 创建一个transport对象
    • 为transport对象创建输入输出protocol
    • 基于输入输出protocol创建processor
    • 等待连接请求并将之交给processor处理
Thrift支持的数据类型
Thrift 脚本可定义的数据类型包括以下几种类型:
  • Base Types:基本类型
  • Struct:结构体类型
  • Container:容器类型,即List、Set、Map
  • Exception:异常类型
  • Service: 定义对象的接口,和一系列方法
Thrift支持的传输格式
Thrift可以让你选择客户端与服务端之间传输通信协议的类别,在传输协议上总体上划分为文本(text)和二进制(binary)传输协议, 为节约带宽,提供传输效率,一般情况下使用二进制类型的传输协议为多数,但有时会还是会使用基于文本类型的协议,这需要根据项目/产品中的实际需求:
  • TBinaryProtocol – 二进制编码格式进行数据传输。
  • TCompactProtocol –高效率的、密集的二进制编码格式进行数据传输,这种协议非常有效的,使用Variable-Length Quantity (VLQ) 编码对数据进行压缩。
  • TJSONProtocol – 使用JSON的数据编码协议进行数据传输。
  • TSimpleJSONProtocol –只提供JSON只写的协议,适用于通过脚本语言解析
  • TDebugProtocol – 在开发的过程中帮助开发人员调试用的,以文本的形式展现方便阅读。
使用Thrift和其他方式的所产生的内容大小比较结果如下:


在上图中我们能明显看出,最臃肿的是RMI,其次是xml,使用Thrift的TCompactProtocol协议和Google 的 Protocol Buffers 相差的不算太多,相比而言还是Google 的 Protocol Buffers效果最佳。
使用Thrift 中的协议和其他方式的所产生的运行开销比较结果如下:

在上图中我们能明显看出,最占资源是REST-XML协议,使用Thrift的TCompactProtocol协议和Google 的 Protocol Buffers 相差的不算太多,相比而言Thrift的TCompactProtocol协议效果最佳。
Thrift支持的传输方式
  • TSocket- 使用堵塞式I/O进行传输,也是最常见的模式。
  • TFramedTransport- 使用非阻塞方式,按块的大小,进行传输,类似于Java中的NIO。
  • TFileTransport- 顾名思义按照文件的方式进程传输,虽然这种方式不提供Java的实现,但是实现起来非常简单。
  • TMemoryTransport- 使用内存I/O,就好比Java中的ByteArrayOutputStream实现。
  • TZlibTransport- 使用执行zlib压缩,不提供Java的实现。
Thrift支持的服务模型
  • TSimpleServer – 单线程服务器端使用标准的堵塞式I/O。常用于测试。
  • TThreadPoolServer – 多线程服务器端使用标准的堵塞式I/O。
  • TNonblockingServer – 多线程服务器端使用非堵塞式I/O,并且实现了Java中的NIO通道。(需使用TFramedTransport数据传输方式)
参考资料:

No comments:

Post a Comment