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