Apache Thrift学习(3):原理与架构解析

基本架构

由上篇学习 Apache Thrift学习(2):Thrift使用入门 的demo基本可以得出如下图所示架构:

Your Code代表客户端和服务端的业务代码

XXXService.Client:与服务端连接、通讯的client对象,用于[Service]接口的方法调用。这里的Service指的是Thrift生成的Service接口层

XXX.write()/read():是Thrift生成的代码,write()是向服务端通过socket写数据,read()是从服务端通过socket接收数据。Thrift生成的相关代码如下:

client示例代码如下:

package com.leolee.thrift.person;

import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

/**
 * @ClassName ThriftClient
 * @Description: Thrift 客户端
 * @Author LeoLee
 * @Date 2020/9/6
 * @Version V1.0
 **/
public class ThriftClient {

    public static void main(String[] args) {

        //服务端transport用的是TFramedTransport,客户端也要用TFramedTransport
        TTransport transport = new TFramedTransport(new TSocket("127.0.0.1", 8899), 60);//对应服务端的传输层方法[TFramed]
        TProtocol protocol = new TCompactProtocol(transport);//对应服务端的协议层方法[TCompact]
        PersonService.Client client = new PersonService.Client(protocol);

        try {
            //打开连接
            transport.open();
            Person person = client.getPersonByName("LeoLee");
            System.out.println("打印getPersonByName请求结果:");
            System.out.println(person.getName());
            System.out.println(person.getAge());
            System.out.println(person.isMarried());

            System.out.println("------------------------");

            Person person2 = new Person();
            person2.setName("LeoLee");
            person2.setAge(25);
            person2.setMarried(false);
            client.savePerson(person2);

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            transport.close();
        }

    }
}

这个示例中,PersonService.Client对象分别调用了service层的 getPersonByName 和 savePerson 两个方法,以getPersonByName 为例查看Thrift生成的代码:

一定是存在了 send_xxx()recv_xxx(),这两个方法一个负责write,一个负责read

send_xxx:

recv_xxx:

最终都会是会调用 TSerializable read write

TProtocol:协议层(应用层),决定以什么样的数据格式来进行数据的传递,强调的是数据的格式。

TTransport:传输层

underlying I/O:实际的网络I/O来传递数据,以字节码的方式在客户端和服务端之间传递

客户端和服务端就是以上面的这个流程,自上而下的执行,互相读写。以上这个架构其实不仅仅限于Thrift,一般的RPC架构都是类似的原理

传输格式

  • TBinaryProtocol:二进制的格式,肯定比文本格式传递数据量小,效率高
  • TCompactProtocol:比TBinaryProtocol的效率更高,将二进制数据进一步压缩为一种“更紧凑”的数据格式
  • TJSONProtocol:文本格式,JSON格式数据
  • TSimpleJSONProtocol:极少使用,提供了JSON只写协议,简单的来讲,这是一种缺少源数据信息的格式,当数据被转化为这种格式后,无法在对端(服务端或者客户端)再反解析为源数据。其内容可以通过脚本语言解析。(说实话,最后的这个通过脚本语言解析,我也没理解什么鬼,查了一下SimpleJSON,大概是一种无法解析字段数据类型的json格式
  • TDebugProtocol:数据调试格式,一种易懂的肉眼可读的文本格式,以便于多端debug(数据传输过程中可抓包截获,分析传递过程中数据的结构等)

数据传输方式

  • TSocket:使用的最少,阻塞式socket
  • TFramedTransport:以frame为单位进行传输,非阻塞式的服务中使用。该传输方式会将传输的数据切分为一个一个的frame
  • TFileTransport:以文件形式传输
  • TMemoryTransport:将内存用于I/O,在Thrift JAVA实现中,内部实际上使用了简单的ByteArrayOutputStream
  • TZlibTransport:使用Zlip对数据进行压缩,与其他传输方式联合使用。当前无JAVA实现。

支持的服务模型

TSimpleServer:简单的单线程服务模型,常用于测试

TThreadPoolServer:多线程服务模型,使用标准的阻塞式IO(类似于一个JAVA的动态线程池,当一个请求到服务端后,会分配一个线程供本次请求使用,当使用完毕后释放,当线程池不够的时候也会创建,同样当有闲置的线程时,也会回收)

TNonblockingServer:多线程服务模型,使用非阻塞IO(需要配合TFrameTransport的数据传输方式)

THsHaServer:THsHa引入了线程池去处理,其模型把读写任务放到线程池处理,提供Half-sync/Half-async的处理模式,Half-sync处理IO事件(accept/read/write io),alf-async用于handler对RPC的同步处理

需要代码的来这里拿嗷:demo项目地址

猜你喜欢

转载自blog.csdn.net/qq_25805331/article/details/108470793