什麼是 Thrift(RPC)?一種介面描述語言和二進位制通訊協議,用來定義和建立跨語言的服務
Table of Contents
Thrift是一種介面描述語言和二進位制通訊協議,它被用來定義和建立跨語言的服務。它被當作一個遠端過程呼叫(RPC)框架來使用,是由Facebook為“大規模跨語言服務開發”而開發的。它通過一個程式碼生成引擎聯合了一個軟體棧,來建立不同程度的、無縫的跨平臺高效服務,可以使用C#、C++(基於POSIX相容系統)、Cappuccino、Cocoa、Delphi、Erlang、Go、Haskell、Java、Node.js、OCaml、Perl、PHP、Python、Ruby和Smalltalk。雖然它以前是由Facebook開發的,但它現在是Apache軟體基金會的開源專案了。該實現被描述在2007年4月的一篇由Facebook發表的技術論文中,該論文現由Apache掌管。
什麼是Thrift
https://www.jianshu.com/p/4723ce380b0e
Protobuf是一個語言中立、平臺中立,對結構化資料進行序列化的可擴充套件機制。
我們在開發的時候開發了一個restful web service,就是基於rest的http呼叫,A系統作為客戶端,B系統作為伺服器端。A系統可以通過URL的方式攜帶一些資料去呼叫B所提供的介面然後返回相應的結果資料。這種方式我們也可以認為是RPC的一種實現方式。對於這種方式我們可以認為是平臺獨立的、語言獨立的,也就是語言中立、平臺中立。也就是我們可以用Python編寫的客戶端去呼叫Java編寫的服務端,因為都是通過URL的方式呼叫。因為URL相當於契約,URL背後的程式碼呼叫者無需關心。
RPC框架呼叫基本模型:如person.getPersonByName(String name),首先客戶端先序列化呼叫資料,傳給服務端,服務端再反序列化提取呼叫資訊,查詢客戶端所需要的資料,完成之後再序列化結果傳回給客戶端。客戶端再反序列化得到結果。
Apache thrift是一個可伸縮的,並且跨語言的一種服務性的開發,他所完成的功能實際上和protobuf是類似的。簡單來說,是Facebook公佈的一款開源跨語言的RPC框架。
架構
Thrift包含一套完整的棧來建立客戶端和服務端程式。頂層部分是由Thrift定義生成的程式碼。而服務則由這個檔案客戶端和處理器程式碼生成。在生成的程式碼裡會建立不同於內建型別的資料結構,並將其作為結果傳送。協議和傳輸層是執行時庫的一部分。有了Thrift,就可以定義一個服務或改變通訊和傳輸協議,而無需重新編譯程式碼。除了客戶端部分之外,Thrift還包括伺服器基礎設施來整合協議和傳輸,如阻塞、非阻塞及多執行緒伺服器。棧中作為I/O基礎的部分對於不同的語言則有不同的實現。
Thrift支援眾多通訊協議:
- TBinaryProtocol – 一種簡單的二進位制格式,簡單,但沒有為空間效率而優化。比文字協議處理起來更快,但更難於除錯。
- TCompactProtocol – 更緊湊的二進位制格式,處理起來通常同樣高效。
- TDebugProtocol – 一種人類可讀的文字格式,用來協助除錯。
- TDenseProtocol – 與TCompactProtocol類似,將傳輸資料的元資訊剝離。
- TJSONProtocol – 使用JSON對資料編碼。
- TSimpleJSONProtocol – 一種只寫協議,它不能被Thrift解析,因為它使用JSON時丟棄了後設資料。適合用指令碼語言來解析。
支援的傳輸協議有:
- TFileTransport – 該傳輸協議會寫檔案。
- TFramedTransport – 當使用一個非阻塞伺服器時,要求使用這個傳輸協議。它按幀來傳送資料,其中每一幀的開頭是長度資訊。
- TMemoryTransport – 使用儲存器對映輸入輸出。(Java的實現使用了一個簡單的ByteArrayOutputStream。)
- TSocket – 使用阻塞的套接字I/O來傳輸。
- TZlibTransport – 用zlib執行壓縮。用於連線另一個傳輸協議。
Thrift還提供眾多的伺服器,包括:
- TNonblockingServer – 一個多執行緒伺服器,它使用非阻塞I/O(Java的實現使用了NIO通道)。TFramedTransport必須跟這個伺服器配套使用。
- TSimpleServer – 一個單執行緒伺服器,它使用標準的阻塞I/O。測試時很有用。
- TThreadPoolServer – 一個多執行緒伺服器,它使用標準的阻塞I/O。
什麼是RPC框架?
https://www.jianshu.com/p/4723ce380b0e
RPC全稱為Remote Procedure Call,意為遠端過程呼叫。
假設有兩臺伺服器A,B.A伺服器上部署著一個應用a,B伺服器上部署著一個應用b,現在a希望能夠呼叫b應用的某個函式(方法),但是二者不在同一個程式內,不能直接呼叫,就需要通過網路傳輸,在AB伺服器之間建一條網路傳輸通道,a把引數傳過去,b接收到引數呼叫自己的方法得到結果,再通過網路傳回給a。
簡單講就是A通過網路來呼叫B的過程,這個過程要涉及的東西很多,比如多執行緒、Socket、序列化反序列化、網路I/O,很複雜。於是牛掰的程式設計師把這些封裝起來做成一套框架供大家使用,就是RPC框架。
thrift通過一箇中間語言IDL(介面定義語言)來定義RPC的資料型別和介面,這些內容寫在以.thrift結尾的檔案中,然後通過特殊的編譯器來生成不同語言的程式碼,以滿足不同需要的開發者。比如java開發者,就可以生成java程式碼,c++開發者可以生成c++程式碼,生成的程式碼中不但包含目標語言的介面定義、方法、資料型別,還包含有RPC協議層和傳輸層的實現程式碼。
Thrift的協議棧結構
Thrift是一種c/s的架構體系。TServer主要任務是高效的接受客戶端請求,並將請求轉發給Processor處理。
- 最上層是使用者自行實現的業務邏輯程式碼;
- Processor是由thrift編譯器自動生成的程式碼,它封裝了從輸入資料流中讀資料和向資料流中寫資料的操作,它的主要工作是:從連線中讀取資料,把處理交給使用者實現impl,最後把結果寫到連線上。
- TProtocol是用於資料型別解析的,將結構化資料轉化為位元組流給TTransport進行傳輸。從TProtocol以下部分是thirft的傳輸協議和底層I/O通訊。
- TTransport是與底層資料傳輸密切相關的傳輸層,負責以位元組流方式接收和傳送訊息體,不關注是什麼資料型別。
- 底層IO負責實際的資料傳輸,包括socket、檔案和壓縮資料流等。
優點
Thrift一些已經明確的優點包括:
- 跟一些替代選擇,比如SOAP相比,跨語言序列化的代價更低,因為它使用二進位制格式。
- 它有一個又瘦又幹淨的庫,沒有編碼框架,沒有XML配置檔案。
- 繫結感覺很自然。例如,Java使用java.util.ArrayList<String>;C++使用std::vector<std::string>。
- 應用層通訊格式與序列化層通訊格式是完全分離的。它們都可以獨立修改。
- 預定義的序列化格式包括:二進位制格式、對HTTP友好的格式,以及緊湊的二進位制格式。
- 兼作跨語言檔案序列化。
- 協議使用軟版本號機制軟體版本管理。Thrift不要求一箇中心化的和顯式的版本號機制,例如主版本號/次版本號。鬆耦合的團隊可以輕鬆地控制RPC呼叫的演進。
- 沒有構建依賴也不含非標準化的軟體。不存在不相容的軟體許可證混用的情況。
建立一個Thrift服務
Thrift由C++編寫,但可以為眾多語言建立程式碼。要建立一個Thrift服務,必須寫一些Thrift檔案來描述它,為目標語言生成程式碼,並且寫一些程式碼來啟動伺服器及從客戶端呼叫它。
Thrift將由這個描述資訊生成獨立的程式碼。例如,在Java裡,PhoneType將是Phone類中一個簡單的enum。
Thrift的第一個java小例項
建立一個服務Hello,建立檔案Hello.thrift,程式碼如下:
namespace java service.demo
service Hello{
string helloString(1:string para)
}
終端進入Hello.thrift所在目錄,執行命令:
thrift -r -gen java Hello.thrift
發現在當前目錄下多了一個gen-java的目錄,裡面的有一個Hello.java的檔案。這個java檔案包含Hello服務的介面定義Hello.Iface,以及服務呼叫的底層通訊細節,包括客戶端的呼叫邏輯Hello.Client以及服務端的處理邏輯Hello.Processor。
建立一個Maven管理的Java專案,pom.xml中新增相關的依賴,並將Hello.java檔案複製到專案中:
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.10.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
建立HelloServiceImpl實現Hello.Iface介面:
package service.demo;
import org.apache.thrift.TException;
public class HelloServiceImpl implements Hello.Iface {
public String helloString(String para) throws TException {
return "result:"+para;
}
}
建立服務端實現程式碼HelloServiceServer,把HelloServiceImpl作為一個具體的處理器傳遞給Thrift伺服器:
public class HelloServiceServer {
/**
* 啟動thrift伺服器
*/
public static void main(String[] args) {
try {
System.out.println("服務端開啟....");
// 1.建立TProcessor
TProcessor tprocessor = new Hello.Processor<Hello.Iface>(new HelloServiceImpl());
// 2.建立TserverTransport
TServerSocket serverTransport = new TServerSocket(9898);
// 3.建立TProtocol
TBinaryProtocol.Factory factory = new TBinaryProtocol.Factory();
TServer.Args tArgs = new TServer.Args(serverTransport);
tArgs.processor(tprocessor);
tArgs.protocolFactory(factory);
// 4.建立Tserver,傳入需要的引數,server將以上內容整合在一起
TServer server = new TSimpleServer(tArgs);
// 5.啟動server
server.serve();
}catch (TTransportException e) {
e.printStackTrace();
}
}
}
建立客戶端實現程式碼HelloServiceClient,呼叫Hello.client訪問服務端的邏輯實現:
public class HelloServiceClient {
public static void main(String[] args) {
System.out.println("客戶端啟動....");
TTransport transport = null;
try {
transport = new TSocket("localhost", 9898, 30000);
// 協議要和服務端一致
TProtocol protocol = new TBinaryProtocol(transport);
Hello.Client client = new Hello.Client(protocol);
transport.open();
String result = client.helloString("哈哈");
System.out.println(result);
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
} finally {
if (null != transport) {
transport.close();
}
}
}
}
全部工作完成後,下面來測試一下,先執行服務端main方法,在執行客戶端main方法,會在客戶端控制檯列印出:哈哈
。
相關文章
- Thrift RPC 系列教程(1)——Thrift語言RPC
- 更小、更快、更簡單Google ProtoBuf 跨語言通訊協議Go協議
- Thrift協議的服務模型協議模型
- 什麼是協議?| 網路協議定義協議
- 二進位制協議 VS 文字協議協議
- gRPC 的介面描述語言 ProtoBuffer(二)RPC
- 什麼是二進位制?二進位制如何轉換?
- RPC 是通訊協議嗎 ?→ 我們來看下它的演進過程RPC協議
- 什麼是Tomcat?用最簡單的語言描述它Tomcat
- go語言遊戲服務端開發(二)——網路通訊Go遊戲服務端
- Thrift RPC 通訊搭建RPC
- Python程式設計基礎(一)程式語言是什麼?編譯型語言和解釋型語言的區別|Python是什麼?Python程式設計編譯
- 二進位制列印與逆序_C語言(轉)C語言
- go語言遊戲服務端開發(四)——RPC機制Go遊戲服務端RPC
- Solidity語言學習筆記————45、應用二進位制介面(ABI)說明Solid筆記
- 跨語言通訊方案比較
- 中文程式語言——易語言,到底是用來幹什麼的?易語言值得學習嗎?易語言的優勢有什麼?
- 通訊協議和網路協議有什麼區別協議
- mysql二進位制日誌是什麼MySql
- Go語言實現十進位制轉換成二、八、十六進位制Go
- 什麼是靜態語言和動態語言。史上秒懂的大白話翻譯。
- 用 C 語言寫面向的物件是一種什麼樣的體驗物件
- 用C語言寫面向的物件是一種什麼樣的體驗C語言物件
- C語言十進位制,八進位制,十六進位制輸出分析C語言
- 使用Go語言建立WebSocket服務GoWeb
- 使用 Go 語言建立 WebSocket 服務GoWeb
- 為什麼Go是一種設計糟糕的程式語言Go
- 為什麼《七週七語言》選中的是這幾種語言?
- .Net 8.0 下的新RPC,IceRPC之介面定義語言 [Slice] VS [Protobuf]RPC
- 【c語言】統計一個數二進位制中的1的個數C語言
- Python是什麼語言?Python底層語言是什麼?Python
- 有一種介面,叫語言
- 關於10進位制轉2進位制的C語言程式碼C語言
- 什麼是Go語言?Go語言有什麼特點?Go
- Go是一門什麼樣的語言?Go
- 什麼是r語言R語言
- 什麼是程式語言
- Dubbo 在跨語言和協議穿透性方向的探索:支援 HTTP/2 gRPC協議穿透HTTPRPC