RPC框架之Thrift的入門教程
前言
隨著近些年微服務(wù)的盛行,使得服務(wù)逐漸模塊化,功能化,單個服務(wù)僅僅實現(xiàn)某個特定的功能或者模塊,因此服務(wù)間的調(diào)用變得常見且頻繁,所以高性能且快速響應(yīng)的服務(wù)調(diào)用成了必須去面對的問題,傳統(tǒng)的http請求能面對跨語言的問題,但是性能遠(yuǎn)遠(yuǎn)無法達(dá)到高并發(fā)的要求,因此更偏向底層的RPC框架越來越受到青睞,像阿里的Dubbo,谷歌的gRPC,facebook的Thrift等等!本節(jié)將學(xué)習(xí)Thrift這個跨語言的Thrift RPC框架!
Thrift簡介
Thrift是一個跨語言的服務(wù)部署框架,最初由Facebook于2007年開發(fā),2008年進(jìn)入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語法學(xué)習(xí)
在學(xué)習(xí)thrift之前,我們需要先簡單的學(xué)習(xí)一下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 | 二進(jìn)制值 |
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的有序列表,允許重復(fù)。類似于java中的ArrayList。
set
元素類型為t的無序表,不允許重復(fù)。類似于java中的HashSet。
map
<t, t>鍵類型為t,值類型為t的鍵值對,鍵不允許重復(fù)。類似于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的命名空間相當(dāng)于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遠(yuǎn)程過程調(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
命令,即可在當(dāng)前目錄下生成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)建一個二進(jìn)制協(xié)議工廠對象。Thrift 支持多種協(xié)議,如 TBinaryProtocol、TCompactProtocol、TJSONProtocol 等,這里選擇的是二進(jìn)制協(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 的套接字對象,連接到在本地主機(jī)(localhost)的9000端口上運(yùn)行的 Thrift 服務(wù)。
TSocket socket = new TSocket("localhost", 9000);
// 創(chuàng)建一個使用二進(jìn)制協(xié)議的實例,該協(xié)議用于在客戶端和服務(wù)器之間傳輸數(shù)據(jù)。
TBinaryProtocol protocol = new TBinaryProtocol(socket);
// 創(chuàng)建一個Thrift 客戶端實例,它使用前面創(chuàng)建的二進(jìn)制協(xié)議實例進(jìn)行通信。
PersonService.Client client = new PersonService.Client(protocol);
// 打開與服務(wù)器端的連接,通過客戶端對象(client)進(jìn)行遠(yuǎn)程過程調(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>運(yùn)行
先啟動服務(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-05
SpringBoot整合WebSocket實現(xiàn)實時通信功能
在當(dāng)今互聯(lián)網(wǎng)時代,實時通信已經(jīng)成為了許多應(yīng)用程序的基本需求,而WebSocket作為一種全雙工通信協(xié)議,為開發(fā)者提供了一種簡單、高效的實時通信解決方案,本文將介紹如何使用SpringBoot框架來實現(xiàn)WebSocket的集成,快速搭建實時通信功能,感興趣的朋友可以參考下2023-11-11
舉例分析Python中設(shè)計模式之外觀模式的運(yùn)用
這篇文章主要介紹了Python中設(shè)計模式之外觀模式的運(yùn)用,外觀模式主張以分多模塊進(jìn)行代碼管理而減少耦合,需要的朋友可以參考下2016-03-03
SpringBoot集成RocketMQ發(fā)送事務(wù)消息的原理解析
RocketMQ 的事務(wù)消息提供類似 X/Open XA 的分布事務(wù)功能,通過事務(wù)消息能達(dá)到分布式事務(wù)的最終一致,這篇文章主要介紹了SpringBoot集成RocketMQ發(fā)送事務(wù)消息,需要的朋友可以參考下2022-06-06
SpringBoot中yml多環(huán)境配置的3種方法
這篇文章主要給大家介紹了SpringBoot中yml多環(huán)境配置的3種方法,文中有詳細(xì)的代碼示例供大家參考,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-10-10
Spring Boot整合Spring Data JPA過程解析
這篇文章主要介紹了Spring Boot整合Spring Data JPA過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10
springboot mybatis調(diào)用多個數(shù)據(jù)源引發(fā)的錯誤問題
這篇文章主要介紹了springboot mybatis調(diào)用多個數(shù)據(jù)源引發(fā)的錯誤問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01
Java實現(xiàn)的求解經(jīng)典羅馬數(shù)字和阿拉伯?dāng)?shù)字相互轉(zhuǎn)換問題示例
這篇文章主要介紹了Java實現(xiàn)的求解經(jīng)典羅馬數(shù)字和阿拉伯?dāng)?shù)字相互轉(zhuǎn)換問題,涉及java輸入輸出及字符串、數(shù)組的遍歷與轉(zhuǎn)換相關(guān)操作技巧,需要的朋友可以參考下2018-04-04

