Thrift基础概念
文章目录
Thrift的网络栈
简单的Thrift网络栈图示
+-------------------------------------------+
| Server |
| (single-threaded, event-driven etc) |
+-------------------------------------------+
| Processor |
| (compiler generated) |
+-------------------------------------------+
| Protocol |
| (JSON, compact etc) |
+-------------------------------------------+
| Transport |
| (raw TCP, HTTP etc) |
+-------------------------------------------+
Transport
传输层为网络的读写提供了一个简单的抽象。这使得Thrift能够将底层传输与系统的其余部分(例如序列化/反序列化)解耦。
以下是Transport接口暴露的一些方法:
- open
- close
- read
- write
- flush
除了上面的Transport接口,Thrift还使用ServerTransport接口来接受或创建原始传输对象。顾名思义,ServerTransport主要用于服务器端,用于为传入连接创建新的Transport对象。
- open
- listen
- accept
- close
以下是大多数thrift支持的语言可以使用的一些传输:
- file: read/write to/from a file on disk 对磁盘上的文件进行读写
- http: as the name suggests 顾名思义
Protocol
协议抽象定义了一种将内存中的数据结构映射到有线格式的机制。换句话说,协议规定了数据类型如何使用底层Transport对自身进行编码/解码。因此,协议实现控制编码方案并负责(反)序列化。在这个意义上,协议的一些例子包括JSON、XML、纯文本、压缩二进制等。
有线格式在广义上指的是用于在内存或硬盘上表达数据的格式,“XML/JSON wire format” 是特定物理表达形式(physical representation,实际表达形式)的实例。其中,对于数据的表达格式,如数据类型等进行了规定。XML/JSON wire format描述的是依据W3C相关技术规范所编写的特定消息/文档的物理表达形式。此类格式之中规定的是用于在运行时环境下解析或写入XML/JSON消息/文档的相关信息。
Protocol 接口:
writeMessageBegin(name, type, seq)
writeMessageEnd()
writeStructBegin(name)
writeStructEnd()
writeFieldBegin(name, type, id)
writeFieldEnd()
writeFieldStop()
writeMapBegin(ktype, vtype, size)
writeMapEnd()
writeListBegin(etype, size)
writeListEnd()
writeSetBegin(etype, size)
writeSetEnd()
writeBool(bool)
writeByte(byte)
writeI16(i16)
writeI32(i32)
writeI64(i64)
writeDouble(double)
writeString(string)
name, type, seq = readMessageBegin()
readMessageEnd()
name = readStructBegin()
readStructEnd()
name, type, id = readFieldBegin()
readFieldEnd()
k, v, size = readMapBegin()
readMapEnd()
etype, size = readListBegin()
readListEnd()
etype, size = readSetBegin()
readSetEnd()
bool = readBool()
byte = readByte()
i16 = readI16()
i32 = readI32()
i64 = readI64()
double = readDouble()
string = readString()
Thrift 协议在设计上面向数据流的。不需要任何明确的框架。例如,在开始序列化之前,我们不需要知道字符串的长度或列表中的items数。大多数支持 Thrift 的语言都可以使用以下协议:
- binary 相当简单的二进制编码–字段的长度和类型以字节形式编码,后面是字段的实际值。
- compact 描述于 THRIFT-110
- json
Processor
处理器封装了从输入流读取数据和向输出流写入数据的能力。输入和输出流由Protocol对象表示。Processor接口非常简单
interface TProcessor {
bool process(TProtocol in, TProtocol out) throws TException
}
特定于服务的处理器实现由编译器生成。处理器本质上是从连接中读取数据(使用输入协议),将处理委托给处理程序(由用户实现),并通过连接(使用输出协议)写入响应。
Server
服务器汇集了上述所有功能:
- 创建传输
- 为传输创建输入/输出协议
- 根据输入/输出协议创建处理器
- 等待传入连接并将其交给处理器
Thrift 的特性
- 接口描述语言–所有内容都在 IDL 文件中指定,可从中生成多种语言的绑定。参见 Thrift IDL
- language bindings - Thrift 支持多种语言和环境
- C++
- C#
- Cocoa
- D
- Delphi
- Erlang
- Haskell
- Java
- OCaml
- Perl
- PHP
- Python
- Ruby
- Smalltalk
- namespaces - 每个Thrift文件都有自己的名称空间,允许您在多个Thrift文件中使用相同的标识符
- language namespaces - 对于Thrift文件,您可以指定每种编程语言应该使用哪个名称空间
- base types - Thrift有一个小的基本类型集。 See Thrift Types
- constants and enumerations - 常量值可以被赋予逻辑名称
- structs -使用structs对相关数据进行分组。结构体可以有任何类型的字段。See Thrift Types
- sparse structs - 尚未设置的可选基本字段和为空的引用字段将不会通过网络发送
- struct evolution - 通过使用字段的整数标识符来处理字段的添加和删除,而不会破坏现有的客户端
- containers - 您可以使用任何类型的sets、lists 和maps :基础类型、structs 和其他容器。See Thrift Types
- type definitions - 任何类型都可以被赋予一个更好地描述它的名称
- services - 服务是一组功能
- service inheritance - 子服务实现其基本服务的所有功能,并且可以具有附加功能
- asynchronous invocations - 可以异步调用不返回结果的函数,这样在服务器完成处理请求之前,客户端不会被阻塞。 服务器可并行/不按顺序执行对同一客户端的异步调用
- exceptions - 如果发生错误,函数可以抛出标准或用户定义的异常。See Thrift Types
- cyclic structs - 从0.9.2版本开始,Thrift支持包含自身的结构,或者稍后声明的其他结构。
不支持的特性
Apache Thrift 不支持以下内容:
- 结构继承 - 使用结构组合代替
- 多态性 - 由于不存在继承,因此也不支持多态性
- 重载–服务中的所有方法都必须唯一命名
- 异构容器 - 容器中的所有项目必须具有相同类型
- 空返回 - 函数不能直接返回Null。请使用包装器结构体或标记值
Thrift 的类型
Thrift类型系统旨在允许程序员尽可能多地使用原生类型,无论他们使用哪种编程语言。此信息基于并取代了Thrift白皮书中的信息。Thrift IDL提供了用于为每种目标语言生成代码的类型的描述。
Base Types
选择基本类型的目标是简单明了,而不是复杂多样,重点关注所有编程语言中可用的关键类型。
- bool: A boolean value (true or false)
- byte: An 8-bit signed integer
- i16: A 16-bit signed integer
- i32: A 32-bit signed integer
- i64: A 64-bit signed integer
- double: A 64-bit floating point number
- string: A text string encoded using UTF-8 encoding
注意没有无符号整数类型。这是因为许多编程语言都没有本地无符号整数类型。
Special Types
binary: a sequence of unencoded bytes 一个未编码的字节序列
注:目前,这是上述字符串类型的一种特殊形式,是为了更好地与 Java 互操作而添加的。目前的计划是在某个时候将其提升为基本类型。
Structs
Thrift 结构定义了一个通用对象–它们本质上等同于 OOP 语言中的类,但没有继承性。结构体有一组强类型字段,每个字段都有一个唯一的名称标识符。字段可以有各种注释(数字字段 ID、可选默认值等),这些注释在Thrift IDL中都有描述。
Containers
Thrift 容器是强类型的容器,可以映射到大多数编程语言中常用和可用的容器类型。
有三种容器类型:
- list: 元素的有序列表。可转换为 STL 向量、Java ArrayList、脚本语言中的本地数组等。
- set: 包含唯一元素的无序集合。可转换为 STL 集合、Java HashSet、Python 中的集合等。注:PHP 不支持集合,因此其处理方式类似于 List
- map<type1,type2>: 严格唯一的键值映射。可转换为 STL map、Java HashMap、PHP 关联数组、Python/Ruby 字典等。虽然提供了默认值,但并没有明确固定类型映射。已添加了自定义代码生成器指令,允许在各种目标语言中替换自定义类型。
容器元素可以是任何有效的 Thrift 类型。
注:为获得最大兼容性,map 的键类型应为基本类型,而不是结构或容器类型。有些语言的本地映射类型不支持更复杂的键类型。此外,JSON 协议只支持基本类型的键类型。
Exceptions
异常在功能上等同于结构体,只不过它们在每种目标编程语言中都继承了原生异常基类,以便与任何特定语言中的本地异常处理无缝集成。
Services
服务使用 Thrift 类型定义。定义服务在语义上等同于在面向对象编程中定义接口(或纯虚拟抽象类)。Thrift 编译器会生成实现接口的功能完备的客户端和服务器存根。
服务由一组命名函数组成,每个函数都有一个参数列表和一个返回类型。
请注意,除了所有其他已定义的 Thrift 类型外,void 也是函数返回的有效类型。此外,还可以在 void 函数中添加单向修饰关键字,这样生成的代码将不会等待响应。请注意,纯 void 函数会向客户端返回一个响应,以保证服务器端的操作已经完成。而单向方法调用只能保证客户端在传输层请求成功。同一客户端的单向方法调用可能会被服务器并行或不按顺序执行。