Thrift協議的服務模型
一、Thrift介紹
Thrift是一個軟體框架,用來進行可擴充套件且跨語言的服務的開發。它結合了功能強大的軟體堆疊和程式碼生成引擎。其允許你定義一個簡單的定義檔案中的資料型別和服務介面。以作為輸入檔案,編譯器生成程式碼用來方便地生成RPC客戶端和伺服器通訊的無縫跨程式語言。
二、Thrift基礎架構
- Thrift 支援的資料型別
1、基本型別
bool: 布林值
byte: 8位有符號整數
i16: 16位有符號整數
i32: 32位有符號整數
i64: 64位有符號整數
double: 64位浮點數
string: UTF-8編碼的字串
binary: 二進位制串
2、結構體型別
struct: 定義的結構體物件
3、容器型別
Thrift容器與型別密切相關,它與當前流行程式語言提供的容器型別相對應,採用java泛型風格表示。Thrift提供了3種容器型別:
list<t1>: 一系列t1型別的元素組成的有序表,元素可以重複
set: <t1>:一系列t1型別的元素組成的無序表,元素唯一
map<t1,t2>:key/value對(key的型別是t1且唯一,value型別是t2)
容器中的元素型別可以是除了service意外的任何合法thrift型別(包括結構體和異常)
4、異常型別:
exception: 異常型別
5、服務型別:
service: 具體對應服務的類
- 協議
Thrift可以讓你選擇客戶端與服務端之間傳輸通訊協議的類別,在傳輸協議上總體上劃分為文字(text)和二進位制(binary)傳輸協議, 為節約頻寬,提供傳輸效率,一般情況下使用二進位制型別的傳輸協議為多數,但有時會還是會使用基於文字型別的協議,這需要根據專案/產品中的實際需求:
1、TBinaryProtocol – 二進位制編碼格式進行資料傳輸。
2、TCompactProtocol – 這種協議非常有效的,使用Variable-Length Quantity (VLQ) 編碼對資料進行壓縮。
3、TJSONProtocol – 使用JSON的資料編碼協議進行資料傳輸。
4、TSimpleJSONProtocol – 這種節約只提供JSON只寫的協議,適用於通過指令碼語言解析
5、TDebugProtocol – 在開發的過程中幫助開發人員除錯用的,以文字的形式展現方便閱讀。
- 傳輸層
1、TSocket- 使用堵塞式I/O進行傳輸,也是最常見的模式。
2、TFramedTransport- 使用非阻塞方式,按塊的大小,進行傳輸,類似於Java中的NIO。
3、TFileTransport- 顧名思義按照檔案的方式程式傳輸,雖然這種方式不提供Java的實現,但是實現起來非常簡單。
4、TMemoryTransport- 使用記憶體I/O,就好比Java中的ByteArrayOutputStream實現。
5、TZlibTransport- 使用執行zlib壓縮,不提供Java的實現。
三、Thrift網路服務模型
Thrif 提供網路模型:單執行緒、多執行緒、事件驅動。從另一個角度劃分為:阻塞服務模型、非阻塞服務模型。
- 阻塞服務
- TSimpleServer:簡單的單執行緒服務模型,主要用於測試
- TThreadPoolServer:多執行緒服務模型,使用標準的阻塞式IO,預先建立一組執行緒處理請求
- 非阻塞服務模型
- TNonblockingServer:多執行緒服務模型,使用非阻塞式IO(需使用TFramedTransport資料傳輸方式),只有一個執行緒來處理消
- THsHaServer:半同步半非同步的服務模型,一個單獨的執行緒用來處理網路I/O,一個worker執行緒池用來進行訊息的處理
- TThreadedSelectorServer:允許你用多個執行緒來處理網路I/O。它維護了兩個執行緒池,一個用來處理網路I/O,另一個用來進行請求的處理
1、TSimpleServer
TSimpleServer實現是非常的簡單,迴圈監聽新請求的到來並完成對請求的處理,是個單執行緒阻塞模型。由於是一次只能接收和處理一個socket連線,效率比較低,在實際開發過程中很少用到它。
/** * 註冊服務端 * 單執行緒服務模型,使用標準的阻塞式IO,只有一個執行緒處理請求 */
public static void startSimpleServer(AdditionService.Processor<AdditionServiceHandler> processor) {
try {
TServerTransport serverTransport = new TServerSocket(9090);// 設定服務埠
// 單執行緒服務模型
TSimpleServer.Args tArgs = new TSimpleServer.Args(serverTransport);
tArgs.processor(processor);
// 客戶端協議要一致
tArgs.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new TSimpleServer(tArgs);
System.out.println("Starting the simple server...");
server.serve();
} catch (Exception e) {
e.printStackTrace();
}
}
2、TThreadPoolServer
ThreadPoolServer為解決了TSimpleServer不支援併發和多連線的問題, 引入了執行緒池。但仍然是多執行緒阻塞模式即實現的模型是One Thread Per Connection。
執行緒池採用能執行緒數可伸縮的模式,執行緒池中的佇列採用同步佇列(SynchronousQueue)。
ThreadPoolServer拆分了監聽執行緒(accept)和處理客戶端連線的工作執行緒(worker), 監聽執行緒每接到一個客戶端, 就投給執行緒池去處理。
/**
* 註冊服務端
* 執行緒池服務模型,使用標準的阻塞式IO,預先建立一組執行緒處理請求
*/
public static void startMultipleServer(AdditionService.Processor<AdditionServiceHandler> processor) {
try {
TServerTransport serverTransport = new TServerSocket(9090);// 設定服務埠
//執行緒池服務模型,使用標準的阻塞式IO,預先建立一組執行緒處理請求。
TThreadPoolServer.Args tArgs = new TThreadPoolServer.Args(serverTransport);
tArgs.processor(processor);
// 客戶端協議要一致
tArgs.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new TThreadPoolServer(tArgs);
System.out.println("Hello TThreadPoolServer....");
server.serve(); // 啟動服務
} catch (Exception e) {
e.printStackTrace();
}
}
這兩個服務端可以處理同樣的客戶端:/**
* 客戶端呼叫
* 阻塞
* Created by Administrator on 2017/1/12.
*/
public class AdditionClient {
public static void main(String[] args) {
try {
TTransport transport;
// 設定傳輸通道
transport = new TSocket("localhost", 9090);//使用堵塞式I/O進行傳輸
transport.open();
// 協議要和服務端一致
// 使用二進位制協議
TProtocol protocol = new TBinaryProtocol(transport);
AdditionService.Client client = new AdditionService.Client(protocol);
System.out.println(client.add(100, 200));
transport.close();
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException x) {
x.printStackTrace();
}
}
}
TThreadPoolServer模式優點:
執行緒池模式中,資料讀取和業務處理都交由執行緒池完成,主執行緒只負責監聽新連線,因此在併發量較大時新連線也能夠被及時接受。執行緒池模式比較適合伺服器端能預知最多有多少個客戶端併發的情況,這時每個請求都能被業務執行緒池及時處理,效能也非常高。
TThreadPoolServer模式缺點:
執行緒池模式的處理能力受限於執行緒池的工作能力,當併發請求數大於執行緒池中的執行緒數時,新請求也只能排隊等待。
3、TNonblockingServer
TNonblockingServer採用單執行緒非阻塞(NIO)的模式, 藉助Channel/Selector機制, 採用IO事件模型來處理。所有的socket都被註冊到selector中,在一個執行緒中通過seletor迴圈監控所有的socket,每次selector結束時,處理所有的處於就緒狀態的socket,對於有資料到來的socket進行資料讀取操作,對於有資料傳送的socket則進行資料傳送,對於監聽socket則產生一個新業務socket並將其註冊到selector中。
/**
* TNonblockingServer採用單執行緒非阻塞(NIO)的模式
* @param processor
*/
public static void nonBlockingServer(AdditionService.Processor<AdditionServiceHandler> processor) {
try {
// 傳輸通道 - 非阻塞方式
TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(9090);// 設定服務埠
// 非同步IO,需要使用TFramedTransport,它將分塊快取讀取。
TNonblockingServer.Args tArgs = new TNonblockingServer.Args(serverTransport);
tArgs.processor(processor);
tArgs.transportFactory(new TFramedTransport.Factory());
// 使用高密度二進位制協議
tArgs.protocolFactory(new TCompactProtocol.Factory());
// 使用非阻塞式IO,服務端和客戶端需要指定TFramedTransport資料傳輸的方式
TServer server = new TNonblockingServer(tArgs);
System.out.println("Starting the simple server...");
server.serve();// 啟動服務
} catch (Exception e) {
e.printStackTrace();
}
}
檢視TNonblockingServer的原始碼,我們可以看到select()方法:private void select() {
try {
this.selector.select();
Iterator e = this.selector.selectedKeys().iterator();
while(!TNonblockingServer.this.stopped_ && e.hasNext()) {
SelectionKey key = (SelectionKey)e.next();
e.remove();
if(!key.isValid()) {
this.cleanupSelectionKey(key);
} else if(key.isAcceptable()) {
this.handleAccept();
} else if(key.isReadable()) {
this.handleRead(key);
} else if(key.isWritable()) {
this.handleWrite(key);
} else {
TNonblockingServer.this.LOGGER.warn("Unexpected state in select! " + key.interestOps());
}
}
} catch (IOException var3) {
TNonblockingServer.this.LOGGER.warn("Got an IOException while selecting!", var3);
}
}
select程式碼裡對accept/read/write等IO事件進行監控和處理, 但由於這是單執行緒處理,所以當遇到handler裡有阻塞的操作時, 會導致整個服務被阻塞住。
TNonblockingServer模式優點:
相比於TSimpleServer效率提升主要體現在IO多路複用上,TNonblockingServer採用非阻塞IO,同時監控多個socket的狀態變化;
TNonblockingServer模式缺點:
TNonblockingServer模式在業務處理上還是採用單執行緒順序來完成,在業務處理比較複雜、耗時的時候,例如某些介面函式需要讀取資料庫執行時間較長,此時該模式效率也不高,因為多個呼叫請求任務依然是順序一個接一個執行。
4、THsHaServer
THsHaServer類是TNonblockingServer類的子類,為解決TNonblockingServer的缺點, THsHa引入了執行緒池去處理, 其模型把讀寫任務放到執行緒池去處理即多執行緒非阻塞模式。HsHa是: Half-sync/Half-async的處理模式,
Half-aysnc是在處理IO事件上(accept/read/write io), Half-sync用於handler對rpc的同步處理上。因此可以認為THsHaServer半同步半非同步。
/**
* THsHaServer
* THsHaServer類是TNonblockingServer類的子類
* @param processor
*/
public static void startTHsHaServer(AdditionService.Processor<AdditionServiceHandler> processor) {
try {
// 傳輸通道 - 非阻塞方式
TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(9090);// 設定服務埠
// 非同步IO,需要使用TFramedTransport,它將分塊快取讀取。
THsHaServer.Args tArgs = new THsHaServer.Args(serverTransport);
tArgs.processor(processor);
tArgs.transportFactory(new TFramedTransport.Factory());
// 使用高密度二進位制協議
tArgs.protocolFactory(new TCompactProtocol.Factory());
// 使用非阻塞式IO,服務端和客戶端需要指定TFramedTransport資料傳輸的方式
TServer server = new THsHaServer(tArgs);
System.out.println("Starting the simple server...");
server.serve();// 啟動服務
} catch (Exception e) {
e.printStackTrace();
}
}
THsHaServer的優點:
與TNonblockingServer模式相比,THsHaServer在完成資料讀取之後,將業務處理過程交由一個執行緒池來完成,主執行緒直接返回進行下一次迴圈操作,效率大大提升;
THsHaServer的缺點:
主執行緒需要完成對所有socket的監聽以及資料讀寫的工作,當併發請求數較大時,且傳送資料量較多時,監聽socket上新連線請求不能被及時接受。
5、TThreadedSelectorServer
TThreadedSelectorServer是大家廣泛採用的服務模型,其多執行緒伺服器端使用非堵塞式I/O模型,是對TNonblockingServer的擴充, 其分離了Accept和Read/Write的Selector執行緒, 同時引入Worker工作執行緒池。
(1)一個AcceptThread執行緒物件,專門用於處理監聽socket上的新連線;
(2)若干個SelectorThread物件專門用於處理業務socket的網路I/O操作,所有網路資料的讀寫均是有這些執行緒來完成;
(3)一個負載均衡器SelectorThreadLoadBalancer物件,主要用於AcceptThread執行緒接收到一個新socket連線請求時,決定將這個新連線請求分配給哪個SelectorThread執行緒。
(4)一個ExecutorService型別的工作執行緒池,在SelectorThread執行緒中,監聽到有業務socket中有呼叫請求過來,則將請求讀取之後,交給ExecutorService執行緒池中的執行緒完成此次呼叫的具體執行
MainReactor就是Accept執行緒, 用於監聽客戶端連線, SubReactor採用IO事件執行緒(多個), 主要負責對所有客戶端的IO讀寫事件進行處理. 而Worker工作執行緒主要用於處理每個rpc請求的handler回撥處理(這部分是同步的)。因此其也是Half-Sync/Half-Async(半非同步-半同步)的 。
TThreadedSelectorServer模式對於大部分應用場景效能都不會差,因為其有一個專門的執行緒AcceptThread用於處理新連線請求,因此能夠及時響應大量併發連線請求;另外它將網路I/O操作分散到多個SelectorThread執行緒中來完成,因此能夠快速對網路I/O進行讀寫操作,能夠很好地應對網路I/O較多的情況。
/**
* TThreadedSelectorServer
* 是多執行緒伺服器端使用非堵塞式I/O模型
* @param processor
*/
public static void startTThreadedSelectorServer(AdditionService.Processor<AdditionServiceHandler> processor) {
try {
// 傳輸通道 - 非阻塞方式
TNonblockingServerSocket serverTransport = new TNonblockingServerSocket(9090);// 設定服務埠
// 非同步IO,需要使用TFramedTransport,它將分塊快取讀取。
TThreadedSelectorServer.Args tArgs = new TThreadedSelectorServer.Args(serverTransport);
tArgs.processor(processor);
tArgs.transportFactory(new TFramedTransport.Factory());
// 使用高密度二進位制協議
tArgs.protocolFactory(new TCompactProtocol.Factory());
// 使用非阻塞式IO,服務端和客戶端需要指定TFramedTransport資料傳輸的方式
TServer server = new TThreadedSelectorServer(tArgs);
System.out.println("Starting the simple server...");
server.serve();// 啟動服務
} catch (Exception e) {
e.printStackTrace();
}
}
上面三種非阻塞服務模型可以處理這樣的客戶端:public static void main(String[] args) {
try {
// 設定傳輸通道,對於非阻塞服務,需要使用TFramedTransport,它將資料分塊傳送
TSocket socket = new TSocket("localhost", 9090);//使用堵塞式I/O進行傳輸
//使用非阻塞方式,按塊的大小,進行傳輸,類似於Java中的NIO
TTransport transport = new TFramedTransport(socket);
// 協議要和服務端一致
// 使用高密度二進位制協議
TProtocol protocol = new TCompactProtocol(transport);
AdditionService.Client client = new AdditionService.Client(protocol);
transport.open();
System.out.println(client.add(100, 100));
transport.close();
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException x) {
x.printStackTrace();
}
}
由於能力有限,文章有很多不足之處,請大家不吝賜教,剩下的程式碼我會上傳原始碼,大家可以下載下來檢視
原始碼
參考:
原始碼
參考:
相關文章
- soap協議的web服務協議Web
- 如何使用thrift 服務引擎元件元件
- Thrift原理分析(二)協議和編解碼協議
- Ajax通過SOAP協議呼叫Web服務協議Web
- dubbo原始碼解析(三十二)遠端呼叫——thrift協議原始碼協議
- syslog協議及rsyslog服務全解析協議
- 真正“搞”懂HTTP協議11之代理服務HTTP協議
- 待機顯示服務協議及隱私政策協議
- 動態主機配置協議DHCP及代理服務協議
- 效能工具之Jmeter壓測Thrift RPC服務JMeterRPC
- 網路通訊協議自動轉換之thrift到http協議HTTP
- 如何在 Istio 中支援 Dubbo、Thrift、Redis 以及任何七層協議?Redis協議
- Python使用socket的UDP協議實現FTP檔案服務PythonUDP協議FTP
- OSI七層模型的功能及協議模型協議
- 測試開發之網路篇-常用服務協議協議
- MQTT協議從服務端到客戶端詳解MQQT協議服務端客戶端
- 什麼是 Thrift(RPC)?一種介面描述語言和二進位制通訊協議,用來定義和建立跨語言的服務RPC協議
- Android實現Thrift服務端與客戶端Android服務端客戶端
- Java呼叫使用SSL/HTTPS協議來傳輸的axis webservice服務JavaHTTP協議Web
- TCP協議服務端和客戶端的連線與通訊TCP協議服務端客戶端
- Automata Network用Rust編寫的去中心化的服務協議Rust中心化協議
- [服務端與網路]http協議與http狀態碼服務端HTTP協議
- Linux網路服務-WebService之【HTTP協議簡介】(一)LinuxWebHTTP協議
- OSI七層模型 -tcp/ip協議模型TCP協議
- dotnet core 開發無縫相容Http和Websocket協議的介面服務HTTPWeb協議
- DHCP協議格式、DHCP服務搭建、DHCP協商互動過程入門學習協議
- RTSP協議、RTMP協議、HTTP協議的區別協議HTTP
- 介面自動化測試:Thrift框架RPC協議客戶端開發框架RPC協議客戶端
- Thrift 客戶端-服務端 零XML配置 註解式配置客戶端服務端XML
- apache cxf-2.4.3 +spring-3.0.5釋出SOAP協議WebService服務ApacheSpring協議Web
- 華為雲簡訊服務教你用C++實現Smgp協議C++協議
- GRIT:eBay基於微服務的分散式事務協議微服務分散式協議
- 【網路協議】IP協議、ARP協議、RARP協議協議
- TCP/IP 協議及網路分層模型TCP協議模型
- Python_17 OSI模型和HTTP協議Python模型HTTP協議
- 華為帳號服務學習筆記(二):OAuth2.0協議詳解筆記OAuth協議
- Istio中的服務和流量的抽象模型抽象模型
- 關於分散式事務、兩階段提交協議、三階提交協議分散式協議