简介
Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的、无缝的跨平台高效服务,可以使用C#、C++(基于POSIX兼容系统)、Cappuccino、Cocoa、Delphi、Erlang、Go、Haskell、Java、Node.js、OCaml、Perl、PHP、Python、Ruby和Smalltalk。虽然它以前是由Facebook开发的,但它现在是Apache软件基金会的开源项目了。该实现被描述在2007年4月的一篇由Facebook发表的技术论文中,该论文现由Apache掌管。
Thrift包含完整的栈来创建客户端和服务端程序。顶层部分是由Thrift定义生成的代码。而服务则由这个文件客户端和处理器代码生成。在生成的代码里会创建不同于内建类型的数据结构,并将其作为结果发送。协议和传输层是运行时库的一部分。有了Thrift,就可以定义一个服务或改变通讯和传输协议,而无需重新编译代码。除了客户端部分之外,Thrift还包括服务器基础设施来集成协议和传输,如阻塞、非阻塞及多线程服务器。栈中作为I/O基础的部分对于不同的语言则有不同的实现。
Thrift支持众多通讯协议:
- TBinaryProtocol – 一种简单的二进制格式,简单,但没有为空间效率而优化。比文本协议处理起来更快,但更难于调试。
- TCompactProtocol – 更紧凑的二进制格式,处理起来通常同样高效。
- TDebugProtocol – 一种人类可读的文本格式,用来协助调试。
- TDenseProtocol – 与TCompactProtocol类似,将传输数据的元信息剥离。
- TJSONProtocol – 使用JSON对数据编码。
- TSimpleJSONProtocol – 一种只写协议,它不能被Thrift解析,因为它使用JSON时丢弃了元数据。适合用脚本语言来解析。
支持的传输协议有:
- TFileTransport – 该传输协议会写文件。
- TFramedTransport – 当使用一个非阻塞服务器时,要求使用这个传输协议。它按帧来发送数据,其中每一帧的开头是长度信息。
- TMemoryTransport – 使用存储器映射输入输出。(Java的实现使用了一个简单的ByteArrayOutputStream。)
- TSocket – 使用阻塞的套接字I/O来传输。
- TZlibTransport – 用zlib执行压缩。用于连接另一个传输协议。
Thrift还提供众多的服务器,包括:
- TNonblockingServer – 多线程服务器,它使用非阻塞I/O(Java的实现使用了NIO通道)。TFramedTransport必须跟这个服务器配套使用。
- TSimpleServer – 单线程服务器,它使用标准的阻塞I/O。测试时很有用。
- TThreadPoolServer – 多线程服务器,它使用标准的阻塞I/O。
Thrift一些已经明确的优点包括:
- 跟一些替代选择,比如SOAP相比,跨语言序列化的代价更低,因为它使用二进制格式。
- 它有一个又瘦又干净的库,没有编码框架,没有XML配置文件。
- 绑定感觉很自然。例如,Java使用java.util.ArrayList<String>;C++使用std::vector<std::string>。
- 应用层通讯格式与序列化层通讯格式是完全分离的。它们都可以独立修改。
- 预定义的序列化格式包括:二进制格式、对HTTP友好的格式,以及紧凑的二进制格式。
- 兼作跨语言文件序列化。
- 协议使用软版本号机制软件版本管理。Thrift不要求一个中心化的和显式的版本号机制,例如主版本号/次版本号。松耦合的团队可以轻松地控制RPC调用的演进。
- 没有构建依赖也不含非标准化的软件。不存在不兼容的软件许可证混用的情况。
安装
以ubuntu 为例
# apt install thrift-compiler
# pip3 install thrift
快速入门
定义接口文档
service Example {
string ping(),
void say(1:string msg)
}
服务器端 server.py
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.server import TServer
from pygen.example import Example
class ExampleHandler:
def __init__(self):
self.log = {}
def ping(self):
return "pong"
def say(self, msg):
print(msg)
handler = ExampleHandler()
processor = Example.Processor(handler)
transport = TSocket.TServerSocket(port=30303)
tfactory = TTransport.TBufferedTransportFactory()
pfactory = TBinaryProtocol.TBinaryProtocolFactory()
server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
print("Starting python server...")
server.serve()
print("done!")
客户端 client.py
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from pygen.example import Example
try:
transport = TSocket.TSocket('localhost', 30303)
transport = TTransport.TBufferedTransport(transport)
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = Example.Client(protocol)
transport.open()
print(client.ping())
client.say('Hello from Python!')
transport.close()
except Thrift.TException as tx:
print(tx.message)
执行:
$ thrift -out pygen/ --gen py example.thrift
$ python3 server.py
Starting python server...
Hello from Python!
$ python3 client.py
pong
参考资料
- 讨论qq群144081101 591302926 567351477 钉钉免费群21745728
- 本文最新版本地址
- 本文涉及的python测试开发库 谢谢点赞!
- 本文相关海量书籍下载
- https://github.com/bayandin/thrift-examples
- https://thrift.apache.org/tutorial/py
- 本文部分内容节选自 书籍 学习Apache Thrift