RPC框架之Thrift的入门教程

 更新时间:2023年10月07日 09:57:09   作者:爱音斯坦牛  
Thrift是一个跨语言的服务部署框架,主要用于各个服务之间的RPC通信,支持跨语言,下面小编就来和大家讲讲Thrift框架的具体使用,希望对大家有所帮助

前言

随着近些年微服务的盛行,使得服务逐渐模块化,功能化,单个服务仅仅实现某个特定的功能或者模块,因此服务间的调用变得常见且频繁,所以高性能且快速响应的服务调用成了必须去面对的问题,传统的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.service
struct 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 person.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 {
    @Override
    public Person getByName(String name) throws TException {
        return new Person(name,18);
    }
    @Override
    public 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调用!

到此这篇关于RPC框架之Thrift的入门教程的文章就介绍到这了,更多相关RPC Thrift内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于@DS注解切换数据源失败的原因实战记录

    关于@DS注解切换数据源失败的原因实战记录

    项目配置了多个数据源,需要使用@DS注解来切换数据源,但是却遇到了问题,下面这篇文章主要给大家介绍了关于@DS注解切换数据源失败原因的相关资料,需要的朋友可以参考下
    2023-05-05
  • SpringBoot整合WebSocket实现实时通信功能

    SpringBoot整合WebSocket实现实时通信功能

    在当今互联网时代,实时通信已经成为了许多应用程序的基本需求,而WebSocket作为一种全双工通信协议,为开发者提供了一种简单、高效的实时通信解决方案,本文将介绍如何使用SpringBoot框架来实现WebSocket的集成,快速搭建实时通信功能,感兴趣的朋友可以参考下
    2023-11-11
  • JAVA不使用线程池来处理的异步的方法详解

    JAVA不使用线程池来处理的异步的方法详解

    这篇文章主要介绍了JAVA不使用线程池来处理的异步的方法,在这个示例中,asyncTask方法创建了一个新的线程来执行异步任务,这个新线程会立即开始执行,而主线程则会继续执行后续的代码,感兴趣的朋友跟随小编一起看看吧
    2024-05-05
  • 举例分析Python中设计模式之外观模式的运用

    举例分析Python中设计模式之外观模式的运用

    这篇文章主要介绍了Python中设计模式之外观模式的运用,外观模式主张以分多模块进行代码管理而减少耦合,需要的朋友可以参考下
    2016-03-03
  • SpringBoot集成RocketMQ发送事务消息的原理解析

    SpringBoot集成RocketMQ发送事务消息的原理解析

    RocketMQ 的事务消息提供类似 X/Open XA 的分布事务功能,通过事务消息能达到分布式事务的最终一致,这篇文章主要介绍了SpringBoot集成RocketMQ发送事务消息,需要的朋友可以参考下
    2022-06-06
  • SpringBoot中yml多环境配置的3种方法

    SpringBoot中yml多环境配置的3种方法

    这篇文章主要给大家介绍了SpringBoot中yml多环境配置的3种方法,文中有详细的代码示例供大家参考,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2023-10-10
  • Spring Boot整合Spring Data JPA过程解析

    Spring Boot整合Spring Data JPA过程解析

    这篇文章主要介绍了Spring Boot整合Spring Data JPA过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • springboot mybatis调用多个数据源引发的错误问题

    springboot mybatis调用多个数据源引发的错误问题

    这篇文章主要介绍了springboot mybatis调用多个数据源引发的错误问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java实现的求解经典罗马数字和阿拉伯数字相互转换问题示例

    Java实现的求解经典罗马数字和阿拉伯数字相互转换问题示例

    这篇文章主要介绍了Java实现的求解经典罗马数字和阿拉伯数字相互转换问题,涉及java输入输出及字符串、数组的遍历与转换相关操作技巧,需要的朋友可以参考下
    2018-04-04
  • java使用UDP实现点对点通信

    java使用UDP实现点对点通信

    这篇文章主要为大家详细介绍了java使用UDP实现点对点通信,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06

最新评论