Thrift簡介及安裝

【thrift是什麼】

thrift的全名叫做Apache thrift,是一款軟件開發RPC框架,可以很高效地實現跨語言的RPC服務。

如果你還不瞭解RPC是什麼,趕快看看這裏

如果想參觀參觀thrift的官方網站,請點擊這裏

【thrift生於何地】

thrift最初生於Facebook,並茁壯成長,在2007年由Facebook正式開源出來,2008年由Apache軟件基金會開始負責項目孵化直至今日。

【還有哪些RPC框架】

protobuf、Avro、MessagePack等,如果你有興趣,可以搜索一下他們,也有利於你更好的瞭解RPC這個領域的發展情況。

【下載thrift】

目前的最新版本是thrift-0.9.1

【安裝thrift】

首先建議你安裝如下這些軟件包:

automake libtool flex bison pkgconfig gcc-c++ boost-devel 
libevent-devel zlib-devel python-devel ruby-devel

然後從官網下載thrift源碼包,並進行編譯鏈接:

./configure –-prefix=/your/program/path/ --enable-libtool-lock
make
make install

安裝完成後,你會看到thrift其實包含了三部分:一個bin程序、一坨頭文件和若干庫文件

【爲什麼需要thrift】

如果你之前沒有接觸過RPC框架的話,可能理解起來會比較困難。爲了照顧這些新用戶的感受,我嘗試着用一種好理解的思路來解釋:

研發工程師小吳接到了一個新任務,給“托福考試成績數據庫”增加一個“成績查詢”的功能,客戶端提供“用戶ID”向服務器端發起查詢請求,服務器端接到查詢請求後從數據庫中取回此用戶ID對應的姓名和成績,並返回給客戶端。

就是這樣一個簡單的Client-Server通信過程,其實就形成了一個典型的RPC場景。服務器端提供“成績查詢服務”,客戶端會通過約定的方法來查詢成績。

小吳設計的方法調用和數據傳輸是這樣的:

thrift example

thrift example

 

通過上圖可以看到,服務器端處於監聽狀態(等待請求的到來),客戶端發起一個名爲Search的動作,參數是用戶ID,而這個動作的返回是一個結構體struct UserGradeInfo,其中包含了用戶的名字(UserName)和用戶的成績(UserGrade)。

設計做完了,小吳要開始編碼了。如果按照“手工作坊”的思路,小吳至少需要完成如下幾個方面:

(1)“客戶端向服務器端發送數據”的代碼

(2)“客戶端接收服務器端查詢結果”的代碼

(3)“服務器端接收客戶端數據”的代碼

(4)“服務器端向客戶端發送查詢結果”的代碼

(5)如果客戶端會大批量發起查詢,那可能還需要考慮改成多線程模型或異步模型

(6)而且還有可能因爲某種原因,要求客戶端和服務器端使用不同的語言進行開發

照此思路,小吳至少要3周時間來開發和自測。(時間很長,對吧)

但,自從thrift出現後(更準確的說,是自從RPC開發框架出現後),上述工作量被大大簡化了。我們只要調用一個thrift工具就可以自動生成上述的所有代碼,即便服務器端和客戶端使用不同的語言,thrift也照樣支持。

至此,我相信你應該大概理解thrift能幫我們做什麼了吧。

【thrift到底怎麼用】

依然拿上面的“成績數據庫”的例子來說,thrift的使用可以被分爲四步:

第1步: 明確要交互的數據格式(如上例中的UserGradeInfo)和具體的方法(如上例中的Search),定義出thrift接口描述文件(英文叫做Inteface Description File);

第2步: 調用thrift工具,依據thrift接口文件,生成RPC代碼;

第3步: 你的服務器端程序引用thrift生成的RPC代碼,並實現其中的Search動作的邏輯,然後啓動監聽,等待客戶端發來請求。

第4步: 客戶端同樣引入並調用RPC代碼來與服務器端通信;

(如果你覺得這樣描述太空虛,別急,稍後會有完整的例子)

【thrift接口描述文件怎麼編寫】

如果你是學院派,那麼我推薦你研究thrift IDL(Interface Definition Language)規範,在這裏。雖然有些晦澀,但你可以從中瞭解到一個接口文件可以如何來寫。

在編寫接口文件時,需要對你要傳輸的數據設定數據類型,比如UserName是字符串型,UserGrade是整型等。因爲thrift是支持衆多開發語言的,所以thrift提供了一套自己的數據類型編寫規範,只有用這套獨立於任何語言的類型規範來編寫接口文件,thrift才能把它轉換成你指定的那種開發語言的代碼。

thrift中的類型包括基礎類型、結構、容器、異常、服務等幾個部分。(官網中有專門介紹數據類型的頁面,在這裏

【類型 之 基礎類型】

基礎類型,其實非常簡單和明確:

(1)bool:布爾類型(true或false)

(2)byte:8位有符號整數

(3)i16:16位有符號整數

(4)i32:32位有符號整數

(5)i64:64位有符號整數

(6)double:64位浮點數

(7)string:文本字符串,使用UTF-8編碼

(有些細心的同學會詢問“爲什麼不支持無符號整數類型呢?”,這是因爲在很多開發語言中並沒有原生的無符號整型。)

【類型 之 容器】

thrift容器包括了各種語言中最常用的容器,共三種:

(1)list容器:一個元素可重複的有序列表。會被轉換成C++中的vector,Java中的ArrayList,腳本語言中的數組等。

(2)set容器:一個元素不可重複的無序集合。會轉換成C++中的set,Java中的HashSet、Python中的Set等。(熟悉PHP的同學可能會問“PHP並不支持set類型,怎麼辦”,在PHP語言中,thrift會將set容器轉換成List。)

(3)map容器:一個含有多個key:value鍵值對的結構。會被轉換成C++中的map,Java中的HashMap,PHP中的關聯數組,Python/Ruby中的dictionary等。

對於上述三種容器,其元素的類型原則上可以是任何一種thrift類型。但是值得注意的是,map的key類型需要是基礎類型,因爲很多開發語言並不支持map的key類型爲複雜數據類型。

【類型 之 結構體】

結構體類型,在形式上和C/C++中的結構體類型非常相似,就是一坨類型的組合,比如上文圖中的UserGradeInfo便是一個thrift結構體類型。

thrift接口文件中的結構體類型,都會被轉換成一個獨立的類(Class)。類的屬性便是結構體中的各個類型,而類的方法便是對這些類型進行處理的相關函數。

我們來看一個結構體定義的例子:

 

 

?

1

2

3

4

5

6

7

8

9

 

 

struct UserGradeInfo {

1: required string UserName = "Anonymous";

2: required i16 UserGrade = 0;

}

 

 可以看到,結構體中每一個域都有一個正整數標識符,這個標識符並不要求連續,但一旦定義,不建議再進行修改。

另外,每個域前都會有required或optional的限定,前者表示是必填域,後者則表示是可選域。域是可以有默認值的,比如上例中的“Anonymous”和0。

(1)如果一個域設置了required,但是在實際構造結構體時又沒有給這個域賦值,那麼thrift會認爲這是一個異常。

(2)如果一個域設置爲optional且在構造結構體時沒有給這個域賦值,那麼在使用這個結構體時,就會忽略掉這個optional的域。

【類型 之 異常】

除了使用exception來替代struct以外,“異常”這個類型,在語法上和剛纔介紹過的結構體的用法是完全一致的。但是從語義上講,exception和struct卻大相徑庭。exception是在遠程調用發生異常時用來拋出異常用的。

【類型 之 服務】

服務的定義,與面向對象技術中定義一個接口很類似,而這些接口其實就是純虛函數。thrift編譯工具會根據服務的定義來產生相應的方法和函數。

每個服務,都包括了若干個函數,每個函數包括了若干參數和一個返回值(返回值可以是void)。

(小技巧:返回值爲void的函數,你可以在函數名前加上oneway標識符,將此函數以異步模式執行,這樣在調用此函數後,函數會立即返回。)

對於返回void的函數,thrift仍然會確保函數返回,這樣就表示這個函數已被正確執行,且服務器端已有返回信息了。但是如果給void的函數前加上oneway,那麼此函數的返回只能表示數據已經進入傳輸層,並不能表示服務器端已經收到並返回了數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章