1. 基本名词
Types: 为了满足多语言平台的要求,需要提供基本数据类型来进行转换。比如在C++的Map和Python的Dict之间能够相互转换。
Transport: 对于每一种语言,都应该有一个抽象的公共层来完成对应的双向数据传输。
Protocal: 数据需要有一种方式来使用对应的传输层的code,而不用关心传输层的具体实现细节。
Versioning:数据需要有自己的版本号来实现对应的健壮性。
Processing : 产生code来完成RPC调用。
2. 类型
1. Goals:
1. 使用最基本的数据类型,不管上层使用怎么样的编程语言。
2. 不使用动态数据类型,也不需要开发者写对象序列化或者传输的代码(已经封装)。
3. IDL 用来告诉代码生成器如何在多语言之上安全地传输数据。
2. Base Types:
1. 选取了大多数语言中都存在的基本数据类型,忽略了一些语言中特别的类型。(无符号类型), 所有的基本
类型都是有符号的。
2. 基本类型包括bool, byte,i16,i32,i64,double,string。
3. Structs:
1. 提供了一种common的对象来代表面向对象语言中的对象类型,每一个filed都有一个标志符。
2. 每个filed必须有一个标志符和一个给定的默认值。标志符如果没有给定的话,会自动分配一个,但是强烈建议给定标志符,为了方便版本控制。
4. Container:
1. List, set, Map。其中List被翻译成STL中的vector, 或者Java中的ArrayList,set和map类似。
2. 要求对应的基本语言类型支持对应的Thrift的基本数据类型。
3. 在每一种目标语言中,对于每一种定义的类型,生成两个接口,read和write,用于序列化和传输对应的数据结构。
5. Exceptions:
1. 使用Exception关键字来代替对应的structs关键字,得到对应的基本类。
2. 生成的对象继承自每一种语言中的对应的Exception的基类。
6. Services:
1. 提供了服务端的接口调用,通过代码生成器会生成Client端和Server端的桩函数接口,共上层调用使用。
2. 在每一个函数前面可以加上async关键字,这个关键字能够实现对应的一部方法。
3. 一个纯void函数也会返回一个response,用来保证该操作在服务端已经被执行。
4. async call只保证消息在传输层是没有问题的,因此,在使用async的时候需要保证当前的使用环境对于丢包是可以接受的。
3. Transport
1. 接口
1. 传输层用来促进数据传输。一个关键的设计是Thrift将数据传输层和代码生成器分开。
2. 由于抽象的IO炒作产生的tradoff相比起实际的IO操作显得微不足道。
3. 需要满足的基本功能:如何读写数据,不管是在网络中,还是共享内存,还是从磁盘文件中读写。
4. 提供的接口如下:open, close,isOpen, read, write, flush。还有一些用于batch操作的接口
5. 对于TServerTransport,还有接口用来创建对应的Transport对象。如open, listen, accept, close。
2. 实现
1. TSocket 类对于TCP/IP的流式套接字实现了一个通用,简单的接口。
2. TFileTransport类实现了一个抽象接口,用于将磁盘文件导入到数据流中。
3. Utilities
1. 网络传输层设计的支持简单的扩展,比如组合,TBufferdTransport实现在传输层实现了buffer的功能,TFrameTransport实现了数据头定长大小,用于Noblocking传输。TMemoryBuffer允许读和写直接在进程的堆顶完成。
4. Protocal
1. 接口
1. 另外一块主要的部分是thrift中将数据结构和传输层分离,thrift定义了一些传输时的基本类型,但是没有强制定义需要实现的编码格式,只要能被代码生成器识别就好。
2. thrift协议的接口简单明了,支持两种功能:双向有序的消息,基本类型,容器,结构的编码。
2. 结构
1. Thrift中默认使用流式结构来传输对应的协议,这样避免了因为需要分片或者在发送前整体计算带来的性能损失。当有的场景需要使用分片,或者分片的性能优势更加明显的时候,可以使用TFramedTransport这个抽象接口类。
3. 实现
1. Thrift的实现了一个空间高效的二进制协议,所有的数据都以一个扁平的二进制格式存在,整形被转换为网络字节序,字符串在头上加上它的长度,所有的消息和field 头都用它的整数序列号,忽略这些filed中的字符串名字。
2. 我们没有做过多的性能优化,为了代码的整洁和高效。如果有需要,可以加入这些优化方案。
5.Versioning
1. 域标志符
1. Thrift在版本控制上面是健壮的,它可以接受旧客户端过来的请求并正确处理。
2. Thrift中的版本控制是通过域标志符来确定的,thrift结构中的每一项前面都有一个对应的标志符,标志符和数据类型唯一化开item。
3. 为了避免冲突,自动分配的标志符从-1开始递减,人工定义的标志符只能为整数。
4. 在数据是自定义的前提下,当反序列化的时候,thrift的code 生成器可以根据标识符来判断读取到的数据是否对齐,也可以跳过不能识别的域,保证兼容性。
5. 域标志符也可以在参数列表中声。
2. Isset
1. 用来标注必须存在于结构体中的域,如果必须存在,标注为true,这样可以当该域不存在的时候,可以通知上层调用者。
3. 场景分析
1. 4种场景,加减域/新旧client或者server。
4. Protocal/Transport Versioning
1. 实现了TProtocal的抽象接口,用来让协议的实现自己来管理版本。
6. RPC 实现
1. TProcessor
1. 核心类,抽象出client和server的基类,核心功能是处理input和output。
2. Generated code
2. 自动生成client端和server端的调用接口。
3. TServer
1. Tserver 可以有多种实现,来满足不同的需求。如单线程的TSimpleServer, 每个连接一个线程的TThreadedServer, 还有基于线程库的TThreadPoolServer.
2. 开发者可以实现自己的TServer。
7. 实现细节
1. 目标语言
1. C++, Java, Python, Ruby, PHP
2. 尽可能简单的抽象,保留在每一种语言中可以自主开发的空间。
2. 生成的结构体
3. RPC 方法定义
1. RPC call中的方法用string去实现,用一些手段将字符处理的代价尽可能的减少,同时方便编程实现。
4. 服务器和多线程
1. 因为种种原因,没有采用boost的线程库,也没有采用ACE,自己实现了一套机制。
5. 线程模型
1. thfirt的线程库包括三个部分:primitives, thread pool manager, timer manager
2. 每个线程是一个对象,提供了Runnerable接口供使用,Synchronized关键字实现类似java的同步块功能。
6. Thread,Runnable, and shared_ptr
7. ThreadManager
8. TimeManager
9. NonBlocking Operation
10. 编译器
11. TFileTransport
8. Facebook thrift service
1. Search&&logging
1. TFileTransport可以实现对应的结构化logging, 这个logging日志可以用来做线上和线下的处理,可以作为redo log。