RPC框架之Thrift的入門教程
前言
隨著近些年微服務(wù)的盛行,使得服務(wù)逐漸模塊化,功能化,單個服務(wù)僅僅實現(xiàn)某個特定的功能或者模塊,因此服務(wù)間的調(diào)用變得常見且頻繁,所以高性能且快速響應(yīng)的服務(wù)調(diào)用成了必須去面對的問題,傳統(tǒng)的http請求能面對跨語言的問題,但是性能遠遠無法達到高并發(fā)的要求,因此更偏向底層的RPC框架越來越受到青睞,像阿里的Dubbo,谷歌的gRPC,facebook的Thrift等等!本節(jié)將學習Thrift這個跨語言的Thrift RPC框架!
Thrift簡介
Thrift是一個跨語言的服務(wù)部署框架,最初由Facebook于2007年開發(fā),2008年進入Apache開源項目,主要用于各個服務(wù)之間的RPC通信,支持跨語言,常用的語言比如C++, Java, Python, PHP, Ruby, Erlang, Perl, C#, JavaScript, Node.js等都支持。(博主也是一名多語言愛好者,因此對Thrift也比較感興趣,所以在后面,我也會寫java,python 的這兩種語言的RPC調(diào)用。)
IDL介紹
Thrift是一個典型的CS(客戶端/服務(wù)端)結(jié)構(gòu),客戶端和服務(wù)端可以使用不同的語言開發(fā)。既然客戶端和服務(wù)端能使用不同的語言開發(fā),那么一定就要有一種中間語言來關(guān)聯(lián)客戶端和服務(wù)端的語言,沒錯,這種語言就是IDL(Interface Description Language)。
IDL 是一種用于定義接口和數(shù)據(jù)結(jié)構(gòu)的語言,用于描述 Thrift 的服務(wù)接口和數(shù)據(jù)類型。在 Thrift 中使用的是 Thrift 自定義的 IDL 語言,它具有類似于其他接口描述語言的特性。
因此我們需要寫IDL,然后使用Thrift編譯器將IDL轉(zhuǎn)換為對應(yīng)的語言,我們開發(fā)者只需要實現(xiàn)具體的業(yè)務(wù)邏輯,無需關(guān)注底層邏輯!
IDL語法學習
在學習thrift之前,我們需要先簡單的學習一下IDL的語法,很簡單,和其他語言結(jié)構(gòu)差不多。
1.基本類型
類型 | 解釋 |
---|---|
bool | 布爾值 |
byte | 8位有符號整數(shù) |
i16 | 16位有符號整數(shù) |
i32 | 32位有符號整數(shù) |
i64 | 64位有符號整數(shù) |
double | 64位浮點數(shù) |
string | UTF-8編碼的字符串 |
binary | 二進制值 |
2.struct結(jié)構(gòu)體
先看例子:
struct Person { // 定義 Person 結(jié)構(gòu)體 1: required string name; // 姓名,必選字段 2: required i32 age; // 年齡,必選字段 3: optional string sex; // 性別,可選字段 }
如上面所示,它類似C語言的結(jié)構(gòu)體,對應(yīng)java中的Bean,其中 required
修飾的他的值初始化是必傳項。
3.container容器
有三種可用的容器類型:
list
元素類型為t的有序列表,允許重復。類似于java中的ArrayList。
set
元素類型為t的無序表,不允許重復。類似于java中的HashSet。
map
<t, t>鍵類型為t,值類型為t的鍵值對,鍵不允許重復。類似于java中的HashMap。
例如:
struct Test { 1: map<string, User> usermap, 2: set<i32> intset, 3: list<double> doublelist }
4.service服務(wù)
服務(wù)的定義方法在語義上等同于面向?qū)ο笳Z言中的接口。
service PersonService { // 定義 PersonService 服務(wù)接口 Person getByName(1: string name); // 根據(jù)姓名獲取 Person 信息 bool save(1: Person person); // 保存 Person 信息 }
5.枚舉(enum)
枚舉的定義形式和Java的Enum定義差不多,例如:
enum Sex { MALE, FEMALE }
6.異常(exception)
thrift支持自定義exception,規(guī)則和struct一樣,如下:
exception RequestException { 1: i32 code; 2: string reason; }
7.命名空間
thrift的命名空間相當于Java中的package的意思,主要目的是組織代碼。thrift使用關(guān)鍵字namespace定義命名空間,例如:
namespace java com.aniu.service
namespace py example
namespace 后跟的是你要轉(zhuǎn)化的語言以及生成的文件所在的包!
Thrift 編譯器安裝
寫完IDL文件后,我們需要將其轉(zhuǎn)換成對應(yīng)語言!因此,我們需要先安裝Thrift編譯器!這里博主用的Windows,macos和Linux自行下載!
網(wǎng)址:https://dlcdn.apache.org/thrift/0.19.0/thrift-0.19.0.exe
下載安裝完成后,配置完環(huán)境變量,如下圖,可查看版本!后續(xù)在其他語言例如java中引入maven包時,需要對應(yīng)版本!
入門案例
這里編寫一個簡單的入門案例,實現(xiàn)rpc遠程過程調(diào)用!定義thrift 文件 person.thrift
namespace java com.aniu.service struct Person { // 定義 Person 結(jié)構(gòu)體 1: required string name; // 姓名,必選字段 2: required i32 age; // 年齡,必選字段 3: optional string sex; // 性別,可選字段 } service PersonService { // 定義 PersonService 服務(wù)接口 Person getByName(1: string name); // 根據(jù)姓名獲取 Person 信息 bool save(1: Person person); // 保存 Person 信息 }
使用
thrift --gen java person.thrift
命令,即可在當前目錄下生成gen-java目錄,里面即是生成的java代碼!
引入對應(yīng)版本的Maven包
<dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.19.0</version> </dependency>
目錄結(jié)構(gòu)如下:
如上圖,Person和PersonService即為thrift編譯器將IDL轉(zhuǎn)換后生成的java代碼。
業(yè)務(wù)邏輯
PersonService里面有兩個接口,我們需要實現(xiàn)接口,在實現(xiàn)類里面寫業(yè)務(wù)邏輯。
package com.aniu.service.impl; import com.aniu.service.Person; import com.aniu.service.PersonService; import org.apache.thrift.TException; public class PersonServiceImpl implements PersonService.Iface { @Override public Person getByName(String name) throws TException { return new Person(name,18); } @Override public boolean save(Person person) throws TException { return false; } }
服務(wù)端
package com.aniu.server; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.server.TServer; import org.apache.thrift.server.TSimpleServer; import org.apache.thrift.transport.TServerSocket; import com.aniu.service.PersonService; import com.aniu.service.impl.PersonServiceImpl; public class Server { public static void main(String[] args) { try{ // 創(chuàng)建一個新的 Thrift 服務(wù)端套接字,監(jiān)聽在端口 9000 上 TServerSocket socket = new TServerSocket(9000); // 創(chuàng)建一個 PersonService 的 Processor。Processor 是 Thrift 中用于處理請求的接口,它需要一個實現(xiàn)了 PersonService 接口的對象作為參數(shù)。 PersonService.Processor<PersonServiceImpl> processor = new PersonService.Processor<>(new PersonServiceImpl()); // 創(chuàng)建一個二進制協(xié)議工廠對象。Thrift 支持多種協(xié)議,如 TBinaryProtocol、TCompactProtocol、TJSONProtocol 等,這里選擇的是二進制協(xié)議。 TBinaryProtocol.Factory factory = new TBinaryProtocol.Factory(); // 創(chuàng)建一個 TSimpleServer 的參數(shù)對象 args1,并將之前創(chuàng)建的套接字、Processor 和協(xié)議工廠設(shè)置為其屬性。 TServer.Args args1 = new TSimpleServer.Args(socket); args1.processor(processor); args1.protocolFactory(factory); // 使用之前設(shè)置好的參數(shù)創(chuàng)建 TSimpleServer 對象 TSimpleServer tSimpleServer = new TSimpleServer(args1); // 開始執(zhí)行 TSimpleServer,開始監(jiān)聽并處理客戶端的請求。 tSimpleServer.serve(); }catch (Exception e){ System.out.println(e); } } }
客戶端
import com.aniu.service.PersonService; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.transport.TSocket; public class Client { public static void main(String[] args) { try{ // 創(chuàng)建一個 Thrift 的套接字對象,連接到在本地主機(localhost)的9000端口上運行的 Thrift 服務(wù)。 TSocket socket = new TSocket("localhost", 9000); // 創(chuàng)建一個使用二進制協(xié)議的實例,該協(xié)議用于在客戶端和服務(wù)器之間傳輸數(shù)據(jù)。 TBinaryProtocol protocol = new TBinaryProtocol(socket); // 創(chuàng)建一個Thrift 客戶端實例,它使用前面創(chuàng)建的二進制協(xié)議實例進行通信。 PersonService.Client client = new PersonService.Client(protocol); // 打開與服務(wù)器端的連接,通過客戶端對象(client)進行遠程過程調(diào)用(RPC)或其他通信操作 socket.open(); // RPC 調(diào)用 Person person = client.getByName("aniu"); System.out.println(person); }catch (Exception e){ System.out.println(e); } } }
pom.xml
<dependencies> <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.19.0</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> <scope>compile</scope> </dependency> <dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>1.3.5</version> <scope>compile</scope> </dependency> </dependencies>
運行
先啟動服務(wù)端,再啟動客戶端,即可實現(xiàn)RPC調(diào)用!
到此這篇關(guān)于RPC框架之Thrift的入門教程的文章就介紹到這了,更多相關(guān)RPC Thrift內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于@DS注解切換數(shù)據(jù)源失敗的原因?qū)崙?zhàn)記錄
項目配置了多個數(shù)據(jù)源,需要使用@DS注解來切換數(shù)據(jù)源,但是卻遇到了問題,下面這篇文章主要給大家介紹了關(guān)于@DS注解切換數(shù)據(jù)源失敗原因的相關(guān)資料,需要的朋友可以參考下2023-05-05SpringBoot整合WebSocket實現(xiàn)實時通信功能
在當今互聯(lián)網(wǎng)時代,實時通信已經(jīng)成為了許多應(yīng)用程序的基本需求,而WebSocket作為一種全雙工通信協(xié)議,為開發(fā)者提供了一種簡單、高效的實時通信解決方案,本文將介紹如何使用SpringBoot框架來實現(xiàn)WebSocket的集成,快速搭建實時通信功能,感興趣的朋友可以參考下2023-11-11SpringBoot集成RocketMQ發(fā)送事務(wù)消息的原理解析
RocketMQ 的事務(wù)消息提供類似 X/Open XA 的分布事務(wù)功能,通過事務(wù)消息能達到分布式事務(wù)的最終一致,這篇文章主要介紹了SpringBoot集成RocketMQ發(fā)送事務(wù)消息,需要的朋友可以參考下2022-06-06SpringBoot中yml多環(huán)境配置的3種方法
這篇文章主要給大家介紹了SpringBoot中yml多環(huán)境配置的3種方法,文中有詳細的代碼示例供大家參考,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2023-10-10Spring Boot整合Spring Data JPA過程解析
這篇文章主要介紹了Spring Boot整合Spring Data JPA過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-10-10springboot mybatis調(diào)用多個數(shù)據(jù)源引發(fā)的錯誤問題
這篇文章主要介紹了springboot mybatis調(diào)用多個數(shù)據(jù)源引發(fā)的錯誤問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01Java實現(xiàn)的求解經(jīng)典羅馬數(shù)字和阿拉伯數(shù)字相互轉(zhuǎn)換問題示例
這篇文章主要介紹了Java實現(xiàn)的求解經(jīng)典羅馬數(shù)字和阿拉伯數(shù)字相互轉(zhuǎn)換問題,涉及java輸入輸出及字符串、數(shù)組的遍歷與轉(zhuǎn)換相關(guān)操作技巧,需要的朋友可以參考下2018-04-04