学习RPC框架-Thrift日志

2023-12-15 04:42:19

前言

Thrift是一个轻量级、跨语言的远程服务调用框架,最初是由Facebook开发的,后面进入Apache开源项目。他通过自身的IDL中间语言,并借助代码生成引擎生成各种主流语言的RPC服务端/客户端模版代码。

Thrift 支持多种不同的变成语言。包括C++、Java、Python、PHP、Ruby等。

正文

Thrift软件栈分层从下向上分别为:传输层(Transport Layer)、协议层(Protocol Layer)、处理层(Processor Layer)和服务层(Server Layer)。

  • 传输层(Transport Layer):传输层负责直接从网络中读取写入数据,它定义了具体的网络传输协议;比如说TCP/IP传输等。
  • 协议层(Protocol Layer):协议层定义了数据传输格式,负责网络传输数据的序列化反序列化;比如说JSONXML二进制数据等。
  • 处理层(Processor Layer):处理层是由具体的IDL接口描述语言)生成的,封装了具体的底层网络传输序列化方式,并委托给用户实现的Handler进行处理。
  • 服务层(Server Layer):整合上述组件,提供具体的网络线程/IO服务模型,形成最终的服务。

特点:

? 开发速度快
? 接口维护简单
? 多语言支持
? 稳定、使用广泛

数据类型

IDL是一个典型的CS结构,使用与客户端和服务端使用不同语言的调用。
基本类型、特殊类型、集合类型

类型标志描述
基本类型bool布尔值
byte8位有符号整数
i1616位有符号整数
i3232位有符号整数
i6464位有符号整数
double64位浮点数
stringUTF-8编码的字符串
枚举类型enum枚举类型
结构体类型struct定义的结构体对象
容器类型list有序元素列表
set无序不重复元素集合
map无序的key/value集合
特殊类型binary二进制串
异常类型exception异常类型
服务类型service具体对应服务的类

struct有以下一些约束:

  • struct不能继承,但是可以嵌套,不能嵌套自己
  • 其成员都是有明确类型
  • 成员是被正整数编号过的,其中的编号使不能重复的,这个是为了在传输过程中编码使用
  • 成员分割符可以是逗号(,)或是分号(;),而且可以混用
  • 字段会有optional和required之分和protobuf一样,但是如果不指定则为无类型–可以不填充该值,但是在序列化传输的时候也会序列化进去,optional是不填充则不序列化,required是必须填充也必须序列化。
  • 每个字段可以设置默认值
  • 同一文件可以定义多个struct,也可以定义在不同的文件,进行include引入

下面来看看各类型是怎么定义的:

//命名空间-表示java代码会生成路径位org.surpass
namespace java org.surpass
//命名空间-表示python代码会生成路径位org.surpass
namespace py org.surpass

//定义一个实体
struct User {
    1:required i16 id;
    2:string name;
    3:optional bool isMan;
    4:i16 age = "18";
}

//定义一个实体
//required 表示该字段必须存在或者有值
//optional 表示可选
struct Teacher {
    1:required i16 id;
    2:string name;
    3:list<User> userList;
    4:set<User> userSet;
    5:map<i16, User> userMap;
}

//定义一个异常
exception BusException {
    1:i32 errorCode;
    2:string errorMsg;
}

//定义一个业务处理类
service Teach {
    list<User> getUserList(1:i16 teacherId);
    User getUser(1:string name);
    map<i16, User> getUserMap() throws (1:BusException e);
}


//定义一个枚举类
enum UserEnum {
    CLASS1 = 1;
    CLASS2 = 2;
}

那么我们如何根据thrift文件生成javapython 代码?

下载链接:https://thrift.apache.org/docs/install/

下载对应平台的thrift可执行文件,并加入到path环境变量中,这样在终端命令行中任何路径都能使用。

我们使用以下命令:

thrift -gen java gen.thrift
thrift -gen py gen.thrift

结果生成的文件就是这个样子:

org
    └─surpass
            BusException.java
            Teach.java
            Teacher.java
            User.java
            UserEnum.java

**文件解析:业务处理类 Teach.java **
Iface:服务端通过实现 HelloWorldService.Iface 接口,向客户端的提供具体的同步业务逻辑。
AsyncIface:服务端通过实现 HelloWorldService.Iface 接口,向客户端的提供具体的异步业务逻辑。
Client:客户端通过 HelloWorldService.Client 的实例对象,以同步的方式访问服务端提供的服务方法。
AsyncClient:客户端通过 HelloWorldService.AsyncClient 的实例对象,以异步的方式访问服务端提供的服务方法。

Teach 作为业务处理类,我们只要继承里面的接口并且实现方法,实现自己的处理逻辑即可。

//自己实现的接口逻辑
public class TeachImpl implements Teach.Iface {
		@Override
        public List<User> getUserList(short teacherId) throws TException {
            return new ArrayList<User>(){{
                add(new User());
            }};
        }

        @Override
        public User getUser(String name) throws TException {
            return new User((short) 1, name, (short) 20);
        }

        @Override
        public Map<Short, User> getUserMap() throws BusException, TException {
            return null;
        }
}

Thrift的协议

Thrift可以让用户选择客户端服务端之间传输通信协议的类别,在传输协议上总体划分为文本(text)和二进制(binary)传输协议。为节约带宽提高传输效率,一般情况下使用二进制类型的传输协议为多数,有时还会使用基于文本类型的协议,这需要根据项目/产品中的实际需求。常用协议有以下几种:

  • TBinaryProtocol:二进制编码格式进行数据传输
  • TCompactProtocol:高效率的、密集二进制编码格式进行数据传输
  • TJSONProtocol: 使用JSON文本的数据编码协议进行数据传输
  • TSimpleJSONProtocol:只提供JSON只写的协议,适用于通过脚本语言解析

Thrift的传输层

常用的传输层有以下几种:

  • TSocket:使用阻塞式I/O进行传输,是最常见的模式
  • TNonblockingTransport:使用非阻塞方式,用于构建异步客户端
  • TFramedTransport:使用非阻塞方式,按块的大小进行传输,类似于Java中的NIO

Thrift服务端类型

  • TSimpleServer:单线程服务器端,使用标准的阻塞式I/O
  • TThreadPoolServer:多线程服务器端,使用标准的阻塞式I/O
  • TNonblockingServer:单线程服务器端,使用非阻塞式I/O
  • THsHaServer:半同步半异步服务器端,基于非阻塞式IO读写和多线程工作任务处理
  • TThreadedSelectorServer:多线程选择器服务器端,对THsHaServer异步IO模型上进行增强

示例

服务端

public class TeachServer {

    public static void main(String[] args) throws TTransportException {
        TServerSocket socket = new TServerSocket(9111);

        Teach.Processor<TeachImpl> processor = new Teach.Processor<>(new TeachImpl());

        TBinaryProtocol.Factory factory = new TBinaryProtocol.Factory();

        TServer.Args arg = new TSimpleServer.Args(socket);
        arg.processor(processor);
        arg.protocolFactory(factory);

        TSimpleServer server = new TSimpleServer(arg);

        server.serve();

    }

}

客户端

public class TeachClient {

    public static void main(String[] args) throws TException {
        //由于在本机测试所以为localhoust,注意端口要一致
        TSocket tSocket = new TSocket("localhost", 9111);

        TBinaryProtocol tBinaryProtocol = new TBinaryProtocol(tSocket);

        Teach.Client client = new Teach.Client(tBinaryProtocol);

        tSocket.open();

        User user = client.getUser("张三");

        System.out.println(user);

    }
}

总结

今天先写到这里后续再补充。。。。。

文章来源:https://blog.csdn.net/asdfasjfaf/article/details/135006966
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。