Thrift RPC 框架分析
前言
工作中用到Thrift,一直想深入研究一下。今天這篇部落格以提問的方式,分析Thrift的原始碼。文章部分參考自: ofollow,noindex">Thrift原始碼分析 。
本來計劃的題目是:「Thrift RPC 原始碼分析」,可是寫了兩個小時才發現,我根本沒有貼出多少原始碼……因為我是在公司專案原始碼中直接分析的,又不能直接貼在部落格中,遂放棄 o_0
Thrift 有什麼特點?
- 基於二進位制的高效能的編解碼框架
- 基於IO/">NIO的底層通訊
- 相對簡單的服務呼叫模型
- 使用IDL支援跨平臺呼叫
Thrift 的整體架構?
官方文件 Apache Thrift - 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新春版 。