前言
工作中用到 Thrift, 一直想深入研究一下. 今天这篇博客以提问的方式, 分析 Thrift 的源码. 文章部分参考自: Thrift 源码分析 https://www.kancloud.cn/digest/thrift/118984 .
本来计划的题目是:「Thrift RPC 源码分析」, 可是写了两个小时才发现, 我根本没有贴出多少源码...... 因为我是在公司项目源码中直接分析的, 又不能直接贴在博客中, 遂放弃 o_0
Thrift 有什么特点?
基于二进制的高性能的编解码框架
基于 NIO 的底层通信
相对简单的服务调用模型
使用 IDL 支持跨平台调用
Thrift 的整体架构?
官方文档 Apache Thrift - Concepts https://thrift.apache.org/docs/concepts 详细说明了 Thrift 的架构:
- Thrift network stack
- +-------------------------------------------+
- | Server |
- | (single-threaded, event-driven etc) |
- +-------------------------------------------+
- | Processor |
- | (compiler generated) |
- +-------------------------------------------+
- | Protocol |
- | (JSON, compact etc) |
- +-------------------------------------------+
- | Transport |
- | (raw TCP, HTTP etc) |
- +-------------------------------------------+
- Transport
Transport layer 提供了一个从网络 IO 读写的简单抽象, 可以使 Thrift 与底层解耦.
Transport 接口有:
- open
- close
- read
- write
- flush
除了 Transport 接口, 还有一个 ServerTransport, 用来在 server 端创建请求的连接.
- open
- listen
- accept
- close
- Protocol
Protocol 定义了传输数据的序列化, 反序列化机制(JSON,xml,binary,compact binary 等).
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()
- Processor
Processor 封装了读取输入流, 写入输出流的能力, 其中输入流, 输出流都是 Protocol 的对象. 接口很简单:
- interface TProcessor {
- bool process(TProtocol in, TProtocol out) throws TException
- }
其中用户需要实现 TProcessor 接口.
Thrift 的源码实现?
TTransport
TTransport 有很多实现, 其中最重要的就是 TFramedTransport.
客户端的实际使用:
- TSocket socket = new TSocket(host, port);
- socket.setTimeout(timeout);
- TTransport transport = new TFramedTransport(socket);
- TProtocol protocol = new TCompactProtocol(transport);
- transport.open();
- TProtocol
Thrift 主要支持的协议有:
- JSON
- SimpleJSON
- Binary
- Compact Binary
其中 Binary 协议的序列化, 反序列化, 可以参考我的另一篇文章: Thrift 对象序列化, 反序列化 - 字节数组分析.
TServer
解释起来太麻烦, 还是直接贴思维导图吧, 更直观 0_o
TServerTransport
TServerTransport 作为服务器的 Acceptor 抽象, 来监听端口, 创建客户端 Socket 连接.
TNonblockingServerTransport 和 TNonblockingServerSocket 作为非阻塞 IO 的 Acceptor, 封装了 ServerSocketChannel
TServerSocket 作为阻塞同步 IO 的 Acceptor, 封装了 ServerSocket
其他 RPC 框架有哪些?
rpcx: 基于 Go 的服务治理的 rpc 框架, 客户端支持跨语言
grpc: Google 出品的跨语言 rpc 框架, 很弱的 (实验性的) 负载均衡, 测试使用的是 grpc-go
go std rpc: Go 标准库的 rpc, 不支持跨语言(jsonrpc 支持 JSON rpc 1.0)
thrift: 跨语言的 rpc 框架, Facebook 贡献
dubbo: 国内较早开源的服务治理的 Java rpc 框架, 虽然在阿里巴巴内部竞争中落败于 HSF, 沉寂了几年, 但是在国内得到了广泛的应用, 目前 dubbo 项目又获得了支持, 并且 dubbo 3.0 也开始开发
motan: 微博内部使用的 rpc 框架, 底层支持 java, 生态圈往 service mesh 发展以支持多语言
hprose: 国内开发人员开发的一个跨语言的 rpc 框架, 非服务治理但是性能高效
twirp: twitch.tv 刚刚开源的一个 restful 风格的 rpc 框架
go-micro: Go 语言的一个服务治理 rpc 框架, 在测试中发现性能不太好, 所以没有继续测试, 相关的测试代码已在 GitHub 库中
go kit:
腾讯 Tars: 腾讯公司的 rpc 框架
百度 brpc: 百度公司的 rpc 框架
spring cloud:
参考自: 流行的 rpc 框架 benchmark 2018 新春版.
来源: http://www.jianshu.com/p/3a79bf355bfe