文章目錄
1、簡介
thrift官網
Apache Thrift軟件框架用於可伸縮的跨語言服務開發,它將軟件棧和代碼生成引擎結合在一起,以構建在c++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、c#、Cocoa、JavaScript、Node.js、Smalltalk、OCaml和Delphi等語言之間高效、無縫地工作的服務。
Thrift使用C++進行編寫,在安裝使用的時候需要安裝依賴,windows安裝方式見官網即可,本人採用的是Mac如按照官網所說安裝則過於麻煩,因此在這裏推薦使用homebrew的Mac包管理器進行安裝,它會幫助我們安裝需要的依賴。安裝方式:thrift官網介紹安裝方式
2、Thrift IDL
Thrift 採用IDL(Interface Definition Language)來定義通用的服務接口,然後通過Thrift提供的編譯器,可以將服務接口編譯成不同語言編寫的代碼,通過這個方式來實現跨語言的功能。
2.1、基本類型
bool: 布爾值 對應Java中的boolean
byte: 有符號字節 對應Java中的byte
i16: 16位有符號整型 對應Java中的short
i32: 32位有符號整型 對應Java中的int
i64: 64位有符號整型 對應Java中的long
double: 64位浮點型 對應Java中的double
string: 字符串 對應Java中的String
binary: Blob 類型 對應Java中的byte[]
2.2、結構體struct
struct有以下一些約束:
1.struct不能繼承,但是可以嵌套,不能嵌套自己。(0.12.0版本可以支持嵌套自己本身)
2.其成員都是有明確類型
3.成員是被正整數編號過的,其中的編號使不能重複的,這個是爲了在傳輸過程中編碼使用。
4.成員分割符可以是逗號(,)或是分號(;),而且可以混用
5.字段會有optional和required之分和protobuf一樣,但是如果不指定則爲無類型–可以不填充該值,但是在序列化傳輸的時候也會序列化進去,optional是不填充則部序列化,required是必須填充也必須序列化。
6.每個字段可以設置默認值
7.同一文件可以定義多個struct,也可以定義在不同的文件,進行include引入。
舉個簡單的下例子:
struct Person{
1: required string name, //本字段必須填寫
2: optional i32 age = 0; //默認值
3: bool gender //默認字段類型是optional
}
規則:
- 如果required標識的域沒有賦值,Thrift將給予提示;
- 如果optional標識的域沒有賦值,該域將不會被序列化傳輸;
- 如果某個optional標識域有缺省值而用戶沒有重新賦值,則該域的值一直爲缺省值;
- 如果某個optional標識域有缺省值或者用戶已經重新賦值,而不設置它的__isset爲true,也不會被序列化傳輸。
2.3、容器Container
thrift提供三種容器選擇:
- list: 元素類型爲t的有序表,容許元素重複。對應C++的vector和Java的ArrayList或者其他語言的數組集合
- set: 元素類型爲t的無序表不容許元素重複。對應C++中的set和Java中的HashSet和python中的set,php中沒有set需要轉換爲list類型
- map<t, t>: 鍵類型爲t,值類型爲t的kv對,鍵不容許重複。對用C++中的map, Java的HashMap, PHP 對應 array, Python/Ruby 的dictionary
簡單的demo:
struct Test {
1: map<string, Person> usermap,
2: set<i32> intset,
3: list<double> doublelist
}
2.4、枚舉enum
約束
- 編譯器默認從0開始賦值
- 可賦予某個常量某個整數
- 允許常量是十六進制整數
- 末尾無分號
- 給常量賦缺省值時,使用常量的全稱
規則
Thrift不支持枚舉類嵌套,枚舉常量必須是32位的正整數
簡單的demo:
enum HttpStatus {
OK = 200,
NOTFOUND=404
}
2.5、常量定義
使用方法:在變量前面加上const
簡單的例子:
const i32 const_int = 1;
2.6、類型定義
Thrift支持C/C++類型定義
簡單的demo:
typedef i32 myint
typedef i64 usernumber
末尾沒有逗號
2.7、異常Exception
異常在語法和功能上類似於結構體,差別是異常使用關鍵字exception,而且異常是繼承每種語言的基礎異常類。
簡單的demo:
exception MyException {
1: i32 errorCode,
2: string message
}
2.8、服務定義類型Service
服務的定義方法在語義上等同於面嚮對象語言中的接口。
service HiService {
i32 sayInt(1:i32 param)
string sayString(1:string param)
bool sayBoolean(1:bool param)
void sayVoid()
}
2.9、名字空間NameSpace
Thrift中的命名空間類似於C++中的namespace和java中的package,它們提供了一種組織(隔離)代碼的簡便方式。名字空間也可以用於解決類型定義中的名字衝突。
由於每種語言均有自己的命名空間定義方式(如python中有module), thrift允許開發者針對特定語言定義namespace。
簡單的demo:
namespace java com.xtxxtx.test
轉換成
package com.xtxxtx.test
2.10、註釋Comment
Thrift支持C多行風格和Java/C++單行風格。
簡單的小demo:
/**
* This is a multi-line comment.
* Just like in C.
*/
// C++/Java style single-line comments work just as well.
2.11、include
便於管理、重用和提高模塊性/組織性,我們常常分割Thrift定義在不同的文件中。包含文件搜索方式與C++一樣。Thrift允許文件包含其它thrift文件,用戶需要使用thrift文件名作爲前綴訪問被包含的對象,
簡單的demo:
include "test.thrift"
...
struct StSearchResult {
1: in32 uid;
...
}
thrift文件名要用雙引號包含,末尾沒有逗號或者分號。
3、thrift架構
Thrift 包含一個完整的堆棧結構用於構建客戶端和服務器端。下圖描繪了 Thrift 的整體架構:
圖中黃色部分是用戶實現的業務邏輯,褐色部分是根據 Thrift 定義的服務接口描述文件生成的客戶端和服務器端代碼框架,紅色部分是根據 Thrift 文件生成代碼實現數據的讀寫操作。紅色部分以下是 Thrift 的傳輸體系、協議以及底層 I/O 通信,使用 Thrift 可以很方便的定義一個服務並且選擇不同的傳輸協議和傳輸層而不用重新生成代碼。
Thrift 服務器包含用於綁定協議和傳輸層的基礎架構,它提供阻塞、非阻塞、單線程和多線程的模式運行在服務器上,可以配合服務器 / 容器一起運行,可以和現有的 J2EE 服務器 /Web 容器無縫的結合。
4、thrift協議
- TBinaryProtocol —— 二進制編碼格式進行數據傳輸
- TCompactProtocol —— 高效率的、密集的二進制編碼格式進行數據傳輸
- TJSONProtocol —— 使用 JSON 的數據編碼協議進行數據傳輸
- TSimpleJSONProtocol —— 只提供 JSON 只寫的協議,適用於通過腳本語言解析
- TDebugProtocol —— 使用簡單易懂的可讀文本格式,便於debug
5、數據傳輸方式
- TSocket —— 使用阻塞式 I/O 進行傳輸,是最常見的模式
- TFramedTransport —— 使用非阻塞方式,按塊的大小進行傳輸,類似於 Java 中的 NIO
- TFileTransport —— 使用文件形式進行傳輸
- TMemoryTransport —— 將內存用於I/O,Java實現內部實際使用簡單的ByteArrayOutputStream
- TZlibTransport —— 使用Zlib進行壓縮,與其他傳輸方式聯合使用,當前無Java實現
6、服務模型
- TSimpleServer —— 單線程服務器端使用標準的阻塞式 I/O
- TThreadPoolServer —— 多線程服務器端使用標準的阻塞式 I/O
- TNonblockingServer —— 多線程服務器端使用非阻塞式 I/O
- THsHaServer —— THsHa引入線程池去處理,其模型把讀寫任務放到線程池中去處理;Half-sync/ Half-async的處理模式,Half-async在處理I/O事件上(accept/read/write io),Half-sync用於Handler對RPC的同步處理