初探Thrift客戶端非同步模式

發表於2014-01-10

背景

在某專案中,我們廣泛使用thrift作為我們內部介面呼叫的RPC框架,而且基本上都是使用多執行緒請求等待應答的同步模式。但是在一些情況下(例如大資料量同步),如果可以使用非同步模式,可以優化程式結構和提高模組效能。

分析

thrift有提供一套非同步模式供我們使用,首先我們像往常一樣編寫thrift協議檔案。

不同的是,需要加入cpp:cob_type來生成程式碼。生成的程式碼檔案外表與之前的基本相同,但在Test.h和Test.cpp中內涵就豐富了,增加了非同步客戶端和非同步伺服器使用的類。

非同步客戶端程式碼有TestCobClient以及它繼承的虛擬類。

從原始檔上看,非同步功能的核心在於TAsyncChannel,它是用於回撥函式註冊和非同步收發資料。send_pingpong和 recv_pingpong分別向緩衝區(TMemoryBuffer)寫入和讀取資料。而pingpong則通過呼叫TAsyncChannel的 sendAndRecvMessage介面註冊回撥函式。

TAsyncChannel作為介面類定義了三個介面函式。

TAsyncChannel目前為止(0.9.1版本)只有一種客戶端實現類TEvhttpClientChannel,顧名思義它是基於 libevent和http協議實現的。 使用libevent的方法就不在這裡累贅了,主要看下sendAndRecvMessage的實現。

通過向evhttp_request中註冊相應回撥函式respones和傳入回撥例項本身的指標,在相應時候回撥函式中呼叫TEvhttpClientChannel例項的finish介面完成資料接收,並寫入快取中,供應用層獲取使用。

實驗

有文章認為:使用Thrift非同步客戶端需要配合使用對應非同步伺服器才能工作。如果這個觀點成立,我們改造目前程式程式碼的成本就會很高,而且可能會喪失使用Thrift的便捷性。

通過上述程式碼的閱讀,發現唯一的侷限性是伺服器必須使用Http的傳輸層,此外只需要協議層保持一致,並不需要一定使用非同步伺服器。

下面我們通過簡單程式碼基於上文“uctest”的協議實現了一個非同步客戶端和同步伺服器。

伺服器程式碼:

客戶端程式碼:

執行結果如下:

[tangzheng@dev10 server]$ ./demo.serv
[1388639886] recv ping
[1388639886] send pong

[tangzheng@dev10 client]$ ./demo.client
[1388639881] ping
[1388639881] running…
[1388639882] running…
[1388639883] running…
[1388639884] running…
[1388639885] running…
[1388639886] recv:pong

達到非同步客戶端預期的效果。

結果

初步掌握了thrift非同步客戶端的用法,我們即可在需要的時候使用,或者優化當前的程式。 由於這種提供的非同步模式必須基於HTTP傳輸層,使用有一定的侷限性。之後將會繼續研究是否可以在TAsyncChannel的基礎上,開發支援其他傳輸層的介面。

相關文章