当前位置: 首页 > news >正文

RPC 框架之Thrift入门(一)

📋 个人简介

  • 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜
  • 📝 个人主页:馆主阿牛🔥
  • 🎉 支持我:点赞👍+收藏⭐️+留言📝
  • 💬格言:迄今所有人生都大写着失败,但不妨碍我继续向前!🔥
    请添加图片描述

目录

    • 📋 个人简介
  • 前言
    • Thrift简介
    • IDL介绍
    • IDL语法学习
      • 1.基本类型
      • 2.struct结构体
      • 3.container容器
      • 4.service服务
      • 5.枚举(enum)
      • 6.异常(exception)
      • 7.命名空间
    • Thrift 编译器安装
    • 入门案例
      • 业务逻辑
      • 服务端
      • 客户端
      • pom.xml
      • 运行
  • 结语

前言

随着近些年微服务的盛行,使得服务逐渐模块化,功能化,单个服务仅仅实现某个特定的功能或者模块,因此服务间的调用变得常见且频繁,所以高性能且快速响应的服务调用成了必须去面对的问题,传统的http请求能面对跨语言的问题,但是性能远远无法达到高并发的要求,因此更偏向底层的RPC框架越来越受到青睐,像阿里的Dubbo,谷歌的gRPC,facebook的Thrift等等!本节将学习Thrift这个跨语言的Thrift RPC框架!

Thrift简介

Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目,主要用于各个服务之间的RPC通信,支持跨语言,常用的语言比如C++, Java, Python, PHP, Ruby, Erlang, Perl, C#, JavaScript, Node.js等都支持。(博主也是一名多语言爱好者,因此对Thrift也比较感兴趣,所以在后面,我也会写java,python 的这两种语言的RPC调用。)

IDL介绍

Thrift是一个典型的CS(客户端/服务端)结构,客户端和服务端可以使用不同的语言开发。既然客户端和服务端能使用不同的语言开发,那么一定就要有一种中间语言来关联客户端和服务端的语言,没错,这种语言就是IDL(Interface Description Language)。

IDL 是一种用于定义接口和数据结构的语言,用于描述 Thrift 的服务接口和数据类型。在 Thrift 中使用的是 Thrift 自定义的 IDL 语言,它具有类似于其他接口描述语言的特性。

因此我们需要写IDL,然后使用Thrift编译器将IDL转换为对应的语言,我们开发者只需要实现具体的业务逻辑,无需关注底层逻辑!

IDL语法学习

在学习thrift之前,我们需要先简单的学习一下IDL的语法,很简单,和其他语言结构差不多。

1.基本类型

类型解释
bool布尔值
byte8位有符号整数
i1616位有符号整数
i3232位有符号整数
i6464位有符号整数
double64位浮点数
stringUTF-8编码的字符串
binary二进制串

2.struct结构体

先看例子:

struct Person {  // 定义 Person 结构体1: required string name;   // 姓名,必选字段2: required i32 age;       // 年龄,必选字段3: optional string sex;    // 性别,可选字段
}

如上面所示,它类似C语言的结构体,对应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服务

服务的定义方法在语义上等同于面向对象语言中的接口。

service PersonService {  // 定义 PersonService 服务接口Person getByName(1: string name);  // 根据姓名获取 Person 信息bool save(1: Person person);       // 保存 Person 信息
}

5.枚举(enum)

枚举的定义形式和Java的Enum定义差不多,例如:

enum Sex {MALE,FEMALE
}

6.异常(exception)

thrift支持自定义exception,规则和struct一样,如下:

exception RequestException {1: i32 code;2: string reason;
}

7.命名空间

thrift的命名空间相当于Java中的package的意思,主要目的是组织代码。thrift使用关键字namespace定义命名空间,例如:

namespace java com.aniu.service
namespace py example

namespace 后跟的是你要转化的语言以及生成的文件所在的包!

Thrift 编译器安装

写完IDL文件后,我们需要将其转换成对应语言!因此,我们需要先安装Thrift编译器!这里博主用的Windows,macos和Linux自行下载!

网址:https://dlcdn.apache.org/thrift/0.19.0/thrift-0.19.0.exe

下载安装完成后,配置完环境变量,如下图,可查看版本!后序在其他语言例如java中引入maven包时,需要对应版本!
在这里插入图片描述

入门案例

这里编写一个简单的入门案例,实现rpc远程过程调用!
定义thrift 文件 person.thrift

namespace java com.aniu.servicestruct Person {  // 定义 Person 结构体1: required string name;   // 姓名,必选字段2: required i32 age;       // 年龄,必选字段3: optional string sex;    // 性别,可选字段
}service PersonService {  // 定义 PersonService 服务接口Person getByName(1: string name);  // 根据姓名获取 Person 信息bool save(1: Person person);       // 保存 Person 信息
}

使用

thrift --gen java user.thrift

命令,即可在当前目录下生成gen-java目录,里面即是生成的java代码!
在这里插入图片描述
在这里插入图片描述
引入对应版本的Maven包

<dependency><groupId>org.apache.thrift</groupId><artifactId>libthrift</artifactId><version>0.19.0</version></dependency>

目录结构如下:
在这里插入图片描述
如上图,Person和PersonService即为thrift编译器将IDL转换后生成的java代码。

业务逻辑

PersonService里面有两个接口,我们需要实现接口,在实现类里面写业务逻辑。
在这里插入图片描述

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 {@Overridepublic Person getByName(String name) throws TException {return new Person(name,18);}@Overridepublic boolean save(Person person) throws TException {return false;}
}

服务端

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{// 创建一个新的 Thrift 服务端套接字,监听在端口 9000 上TServerSocket socket = new TServerSocket(9000);// 创建一个 PersonService 的 Processor。Processor 是 Thrift 中用于处理请求的接口,它需要一个实现了 PersonService 接口的对象作为参数。PersonService.Processor<PersonServiceImpl> processor = new PersonService.Processor<>(new PersonServiceImpl());// 创建一个二进制协议工厂对象。Thrift 支持多种协议,如 TBinaryProtocol、TCompactProtocol、TJSONProtocol 等,这里选择的是二进制协议。TBinaryProtocol.Factory factory = new TBinaryProtocol.Factory();// 创建一个 TSimpleServer 的参数对象 args1,并将之前创建的套接字、Processor 和协议工厂设置为其属性。TServer.Args args1 = new TSimpleServer.Args(socket);args1.processor(processor);args1.protocolFactory(factory);// 使用之前设置好的参数创建 TSimpleServer 对象TSimpleServer tSimpleServer = new TSimpleServer(args1);// 开始执行 TSimpleServer,开始监听并处理客户端的请求。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{// 创建一个 Thrift 的套接字对象,连接到在本地主机(localhost)的9000端口上运行的 Thrift 服务。TSocket socket = new TSocket("localhost", 9000);// 创建一个使用二进制协议的实例,该协议用于在客户端和服务器之间传输数据。TBinaryProtocol protocol = new TBinaryProtocol(socket);// 创建一个Thrift 客户端实例,它使用前面创建的二进制协议实例进行通信。PersonService.Client client = new PersonService.Client(protocol);// 打开与服务器端的连接,通过客户端对象(client)进行远程过程调用(RPC)或其他通信操作socket.open();// RPC 调用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>

运行

先启动服务端,再启动客户端,即可实现RPC调用!
在这里插入图片描述

结语

本节实现了一个简单的案例,但对于thrift的服务端如何创建的,客户端如何调用没有具体讲解,基本都在注释里,下一篇博文来讲解原理以及实现跨语言RPC调用!

http://www.lryc.cn/news/182948.html

相关文章:

  • 【C++】运算符重载 ⑥ ( 一元运算符重载 | 后置运算符重载 | 前置运算符重载 与 后置运算符重载 的区别 | 后置运算符重载添加 int 占位参数 )
  • 538. 把二叉搜索树转换为累加树
  • java8日期时间工具类
  • 算法-动态规划/trie树-单词拆分
  • React框架核心原理
  • python-pytorch 利用pytorch对堆叠自编码器进行训练和验证
  • 制作 3 档可调灯程序编写
  • 源码分享-M3U8数据流ts的AES-128解密并合并---GoLang实现
  • CSDN Q: “这段代码算是在STC89C52RC51单片机上完成PWM呼吸灯了吗?“
  • Linux系统编程系列之线程池
  • Linux CentOS7 vim多文件与多窗口操作
  • SPI 通信协议
  • 【图像处理】使用各向异性滤波器和分割图像处理从MRI图像检测脑肿瘤(Matlab代码实现)
  • 5个适合初学者的初级网络安全工作,网络安全就业必看
  • Kafka核心原理
  • 探秘前后端开发世界:猫头虎带你穿梭编程的繁忙街区,解锁全栈之路
  • 洛谷_分支循环
  • MySQL数据库入门到精通——进阶篇(3)
  • Mind Map:大语言模型中的知识图谱提示激发思维图10.1+10.2
  • [引擎开发] 杂谈ue4中的Vulkan
  • docker--redis容器部署及地理空间API的使用示例-II
  • Vue中如何进行文件浏览与文件管理
  • jenkins利用插件Active Choices Plug-in达到联动显示或隐藏参数,且参数值可修改
  • 香蕉叶病害数据集
  • 天地无用 - 修改朋友圈的定位: 高德地图 + 爱思助手
  • AtCoder Beginner Contest 232(A-G)
  • 计算机网络(第8版)-第5章 运输层
  • AtCoder Beginner Contest 231(D-F,H)
  • 【Python】map
  • Swift 5.9 与 SwiftUI 5.0 中新 Observation 框架应用之深入浅出