1 Apache Thrift 初识 (1) - 简介

Wu Jun 2019-01-05 17:03:33
10 微服务 > 1 服务调用 > 05 Apache Thrift

【todo】零拷贝

Thrift 是最初由 Facebook 开发的 RPC 框架,适用于程序对程序静态的数据交换,需要先确定好数据结构。

1 特性

2 栈结构

Thrift的栈结构

Thrift 包含三个主要的组件:protocol,transport 和 server。

Thrift的网络栈

2.1 Transport

Transport层提供了一个简单的网络读写抽象层。这使得thrift底层的transport从系统其它部分(如:序列化/反序列化)解耦。

2.2 Protocol

Protocol抽象层定义了一种将内存中数据结构映射成可传输格式的机制。换句话说,Protocol定义了datatype怎样使用底层的Transport对自己进行编解码。因此,Protocol的实现要给出编码机制并负责对数据进行序列化。

2.3 Processor

Processor封装了从输入数据流中读数据和向数据流中写数据的操作。 主要工作流程如下:

2.4 Server

Server将以上所有特性集成在一起:

(1) 创建一个transport对象 (2) 为transport对象创建输入输出protocol (3) 基于输入输出protocol创建processor (4) 等待连接请求并将之交给processor处理

TSimpleServer TNonblockingServer THsHaServer TThreadedSelectorServer TThreadPoolServer

TThreadedSelectorServer 对大多数案例来说都是个安全之选。如果你的系统资源允许运行大量并发线程的话,建议你使用 TThreadPoolServer。

3 调用流程

3.1 服务端编码的基本流程
  1. 创建TTransport
  2. 创建TProtocol
  3. 创建TProcessor
  4. 创建Server
  5. 启动服务
3.2 客户端编码的基本流程
  1. 创建TTransport
  2. 创建TProtocol
  3. 创建Client
  4. client方法调用

4 传输体系

4.1 传输协议

Thrift 支持多种传输协议,用户可以根据实际需求选择合适的类型。Thrift 传输协议上总体可划分为文本 (text) 和二进制 (binary) 传输协议两大类。常用的协议包含:

TBinaryProtocol:是Thrift的默认协议,使用二进制编码格式进行数据传输,基本上直接发送原始数据` TCompactProtocol:压缩的、密集的数据传输协议,基于Variable-length quantity的zigzag 编码格式 TJSONProtocol:以JSON (JavaScript Object Notation)数据编码协议进行数据传输 TDebugProtocol:常常用以编码人员测试,以文本的形式展现方便阅读

4.2 传输方式

与传输协议一样,Thrift 也支持几种不同的传输方式。

  1. TSocket:阻塞型 socket,用于客户端,采用系统函数 read 和 write 进行读写数据。
  2. TServerSocket:非阻塞型 socket,用于服务器端,accecpt 到的 socket 类型都是 TSocket(即阻塞型 socket)。
  3. TBufferedTransport 和 TFramedTransport 都是有缓存的,均继承TBufferBase,调用下一层 TTransport 类进行读写操作吗,结构极为相似。其中 TFramedTransport 以帧为传输单位,帧结构为:4个字节(int32_t)+传输字节串,头4个字节是存储后面字节串的长度,该字节串才是正确需要传输的数据,因此 TFramedTransport 每传一帧要比 TBufferedTransport 和 TSocket 多传4个字节。
  4. TMemoryBuffer 继承 TBufferBase,用于程序内部通信用,不涉及任何网络I/O,可用于三种模式:(1)OBSERVE模式,不可写数据到缓存;(2)TAKE_OWNERSHIP模式,需负责释放缓存;(3)COPY模式,拷贝外面的内存块到TMemoryBuffer。
  5. TFileTransport 直接继承 TTransport,用于写数据到文件。对事件的形式写数据,主线程负责将事件入列,写线程将事件入列,并将事件里的数据写入磁盘。这里面用到了两个队列,类型为 TFileTransportBuffer,一个用于主线程写事件,另一个用于写线程读事件,这就避免了线程竞争。在读完队列事件后,就会进行队列交换,由于由两个指针指向这两个队列,交换只要交换指针即可。它还支持以 chunk(块)的形式写数据到文件。
  6. TFDTransport 是非常简单地写数据到文件和从文件读数据,它的 write 和 read 函数都是直接调用系统函数 write 和 read 进行写和读文件。
  7. TSimpleFileTransport 直接继承 TFDTransport,没有添加任何成员函数和成员变量,不同的是构造函数的参数和在 TSimpleFileTransport 构造函数里对父类进行了初始化(打开指定文件并将fd传给父类和设置父类的close_policy为CLOSE_ON_DESTROY)。
  8. TZlibTransport 跟 TBufferedTransport 和 TFramedTransport一样,调用下一层 TTransport 类进行读写操作。它采用<zlib.h>提供的 zlib 压缩和解压缩库函数来进行压解缩,写时先压缩再调用底层 TTransport 类发送数据,读时先调用 TTransport 类接收数据再进行解压,最后供上层处理。
  9. TSSLSocket 继承 TSocket,阻塞型 socket,用于客户端。采用 openssl 的接口进行读写数据。checkHandshake()函数调用 SSL_set_fd 将 fd 和 ssl 绑定在一起,之后就可以通过 ssl 的 SSL_read和SSL_write 接口进行读写网络数据。
  10. TSSLServerSocket 继承 TServerSocket,非阻塞型 socket, 用于服务器端。accecpt 到的 socket 类型都是 TSSLSocket 类型。
  11. THttpClient 和 THttpServer 是基于 Http1.1 协议的继承 Transport 类型,均继承 THttpTransport,其中 THttpClient 用于客户端,THttpServer 用于服务器端。两者都调用下一层 TTransport 类进行读写操作,均用到TMemoryBuffer 作为读写缓存,只有调用 flush() 函数才会将真正调用网络 I/O 接口发送数据。

参考文档