• 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;    // 性别,可选字段
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如上面所示,它类似C语言的结构体,对应java中的Bean,其中required修饰的他的值初始化是必传项。

    3.container容器

    有三种可用的容器类型:

    • list
      元素类型为t的有序列表,允许重复。类似于java中的ArrayList。
    • set
      元素类型为t的无序表,不允许重复。类似于java中的HashSet。
    • map
      键类型为t,值类型为t的键值对,键不允许重复。类似于java中的HashMap。

    例如:

    struct Test {
        1: map<string, User> usermap,
        2: set<i32> intset,
        3: list<double> doublelist
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.service服务

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

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

    5.枚举(enum)

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

    enum Sex {
        MALE,
        FEMALE
    }
    
    • 1
    • 2
    • 3
    • 4

    6.异常(exception)

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

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

    7.命名空间

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

    namespace java com.aniu.service
    
    • 1
    namespace py example
    
    • 1

    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 信息
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    使用

    thrift --gen java person.thrift
    
    • 1

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

    <dependency>
        <groupId>org.apache.thriftgroupId>
          <artifactId>libthriftartifactId>
          <version>0.19.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    目录结构如下:
    在这里插入图片描述
    如上图,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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    服务端

    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);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    客户端

    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);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    pom.xml

    <dependencies>
        <dependency>
          <groupId>org.apache.thriftgroupId>
          <artifactId>libthriftartifactId>
          <version>0.19.0version>
        dependency>
        <dependency>
          <groupId>org.slf4jgroupId>
          <artifactId>slf4j-log4j12artifactId>
          <version>1.7.5version>
        dependency>
        <dependency>
          <groupId>org.slf4jgroupId>
          <artifactId>slf4j-apiartifactId>
          <version>1.7.30version>
          <scope>compilescope>
        dependency>
        <dependency>
          <groupId>jakarta.annotationgroupId>
          <artifactId>jakarta.annotation-apiartifactId>
          <version>1.3.5version>
          <scope>compilescope>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    运行

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

    结语

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

  • 相关阅读:
    Python合并同类别且相交的矩形框
    如何提升网站排名和用户体验:优化网站速度
    python神经网络实现手写数字识别实验
    监控易一体化运维:打造机房环境监控的卓越典范
    [附源码]SSM计算机毕业设计在线购物系统JAVA
    C语言 指针进阶 壹
    机器学习笔记之高斯混合模型(一)模型介绍
    【Python百宝箱】Python测试工具大揭秘:从单元测试到Web自动化
    介绍grpc
    如何将PDF文件转换成Excel呢?
  • 原文地址:https://blog.csdn.net/qq_57421630/article/details/133588555