1001
技術社區[雲棲]
Apache Thrift使用總結
使用感受
之前對Thrift的理解有點不準確,使用之後發現Thrift比想象中的要簡單得多。
Thrift做的事情就是跨語言的分布式RPC,通過編寫.thrift文件聲明接口類和方法,客戶端調用定義的方法,Server端實現定義的接口。雖然的確RPC是需要網絡請求,但不像Netty這種NIO網絡編程庫(還要關注很多數據傳輸中的細節,比如數據如何序列化、如何在字節數組裏建立結構、如何在兩端解析字節數組、如何處理Handler裏的事件狀態、如何把多個Handler按順序串起來),Thrift掩蓋了數據傳輸這件事情,開發者使用的時候就是純純的RPC的使用感受。基本使用
Thrift使用起來幾乎沒有任何門檻,可以看這篇HelloWorld的文章,雖然有點老,但是看完之後基本使用起來沒有任何障礙了。
官方給出的這個例子更加全麵些,全麵在.thrift文件裏可以聲明的東西列的更全些。
下麵看看兩個.thrift的定義:shared.thrift
/**
* This Thrift file can be included by other Thrift files that want to share
* these definitions.
*/
namespace java com.baidu.mordor.sink.service
struct SharedStruct {
1: i32 key
2: string value
}
service SharedService {
SharedStruct getStruct(1: i32 key)
}
tutorial.thrift
/**
* The first thing to know about are types. The available types in Thrift are:
*
* bool Boolean, one byte
* byte Signed byte
* i16 Signed 16-bit integer
* i32 Signed 32-bit integer
* i64 Signed 64-bit integer
* double 64-bit floating point value
* string String
* binary Blob (byte array)
* map<t1,t2> Map from one type to another
* list<t1> Ordered list of one type
* set<t1> Set of unique elements of one type
*
* Did you also notice that Thrift supports C style comments?
*/
// Just in case you were wondering... yes. We support simple C comments too.
/**
* Thrift files can reference other Thrift files to include common struct
* and service definitions. These are found using the current path, or by
* searching relative to any paths specified with the -I compiler flag.
*
* Included objects are accessed using the name of the .thrift file as a
* prefix. i.e. shared.SharedObject
*/
include "shared.thrift"
/**
* Thrift files can namespace, package, or prefix their output in various
* target languages.
*/
namespace java com.baidu.mordor.sink.service
/**
* Thrift lets you do typedefs to get pretty names for your types. Standard
* C style here.
*/
typedef i32 MyInteger
/**
* Thrift also lets you define constants for use across languages. Complex
* types and structs are specified using JSON notation.
*/
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
/**
* You can define enums, which are just 32 bit integers. Values are optional
* and start at 1 if not supplied, C style again.
*/
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}
/**
* Structs are the basic complex data structures. They are comprised of fields
* which each have an integer identifier, a type, a symbolic name, and an
* optional default value.
*
* Fields can be declared "optional", which ensures they will not be included
* in the serialized output if they aren't set. Note that this requires some
* manual management in some languages.
*/
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}
/**
* Structs can also be exceptions, if they are nasty.
*/
exception InvalidOperation {
1: i32 what,
2: string why
}
/**
* Ahh, now onto the cool part, defining a service. Services just need a name
* and can optionally inherit from another service using the extends keyword.
*/
service Calculator extends shared.SharedService {
void ping(),
i32 add(1:i32 num1, 2:i32 num2),
i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),
/**
* This method has a oneway modifier. That means the client only makes
* a request and does not listen for any response at all. Oneway methods
* must be void.
*/
oneway void zip()
}
Thrift通過IDL(接口定義語言),在.thrift文件裏聲明接口類和方法,聲明struct結構、const、Exception等,還可以include別的.thrift文件,這套語法與C非常相似。通過編寫IDL和generate代碼,做到了不同語言之間的RPC,客戶端實現接口類和使用結構類的時候非常簡單好用。
上麵例子的代碼可以從官方下載到,可以放到本地看一下他的使用,非常簡單。
Thrift重要組件
Thrift API裏三個重要組成部分:Protocal,Transport,Server。
Protocal定義了消息如何序列化。常見的是TBinaryProtocol,TJSONProtocol,TCompactProtocol。
Transport定義了消息在客戶端和服務端如何通信。常見的是TSocket,TFramedTransport,TNonblockingTransport等。
TServer說明
Thrift實現的幾種不同的TServer。對於Java而言,版本按0.9.0為準:TSimpleServer在sever端隻有一個I/O阻塞的單線程,每次隻接受並服務一個客戶端,適合測試使用,不能用於線上服務。
TNonblockingServer修改了TSimpleServer裏阻塞的缺點,借助NIO裏的Selector實現非阻塞I/O,允許多個客戶端連接並且客戶端可以使用select()選擇。但是處理消息和select()的是同一個線程,當有大量客戶端連接的時候,性能是不理想的。
THsHaServer(半同步半異步server)在以上基礎上,使用一個單獨線程來處理網絡I/O,一個worker線程池來處理消息。好處是隻要有空閑worker線程,消息可以被及時、並行處理,吞吐量會大一些。
TThreadedSelectorServer,與THsHaServer的區別是處理網絡I/O也是多線程了,它維護兩個線程池,一個負責網絡I/O,一個負責數據處理。優點是當網絡I/O是瓶頸的情況下,性能比THsHaServer更好。
TThreadPoolServer有一個專用的線程來接收connections,連接被建立後,會從ThreadPoolExecutor裏取一個工作線程來負責這次連接,直到連接斷開後線程回到線程池裏,且線程池大小可配。也就是說,並發性的大小可根據服務器設定,如果不介意開很多線程的話,TThreadPoolServer是個還不錯的選擇。
全文完 :)
最後更新:2017-04-03 07:57:02