RPC的实现原理(thrift/dubbo比较)

1.概念

我们知道RPC的目的就是让Client像本地方法一样去调用远程(即Server)服务,而完成这一功能,从上至下,Server需要完成方法的包装序列化,以及负责实现网络通信和方法的具体实现;同样Client调用,首先也得持有方法对象,然后将方法以及参数序列化后,和Server通信,交由Server具体实现,最后Server返回响应的结果。
https://www.cnblogs.com/crazylqy/p/7995395.html
总结一下,RPC框架需要解决的问题:1. 网络通信 2. 序列化/反序列化 3. 透明化服务调用。下面一一分析。

2.透明化服务调用

这也是RPC最直接的目的,Client需要像调用本地方法一样调用Server端的方法,所以在Client和Server端中间必须有一个虚拟桥梁,那就是对象方法服务接口,所以Client和Server都需要持有这个对象方法服务接口。一般而言,都是Server端定义好了对象方法接口,并负责具体的实现,然后将对象方法接口告知Client,然后Client也需要在本地创建一个对象方法接口,并不需要具体实现。这样Client就可以调用接口方法,然后由RPC框架负责序列化参数,并交由服务端的具体实现来完成。
对于不同的框架而言,实现方式有点不同:

  • Dubbo:通过java反射和动态代理实现这一功能,由于只支持Java,所以Client和Server端开发语言机制一样,所以它们能够通过spring框架进行依赖,server端一般将对象方法接口注册发布到Zookeper中,然后Client可以直接从Zookeper中获取server端发布的对象方法接口,这样Client可以通过Spring进行自动装配获得server端发布的对象方法服务接口。
  • Thrift:通过IDL(接口定义语言)实现,Thrift是支持跨语言的,而要实现跨语言机制,就需要一种中间语言来完成,那就是IDL。首先定义好了IDL之后(即定义好了一个service),由于server和Client都需要持有这个与之语言相对应的服务接口,那就需要thrift来将IDL编译成与之语言相对应的接口类,比如server端是java,client端是C#,则server端需要编译成java类,client编译成C#类。然后server端负责接口的具体实现,client只需要持有这个对象接口,进行调用即可,然后通过网络通信传给server。server负责解析client传递过来的数据,由于服务对象接口统一为IDL(thrift格式),所以统一了解析形式,只和本地的开发语言有关。

3.网络通信

【thrift的实现】

  • thrift的网络通信是自己开发实现的,下面为其架构图
    在这里插入图片描述

  • TProtocol(协议层),定义数据传输格式,例如:
    TBinaryProtocol:二进制格式;
    TCompactProtocol:压缩格式;
    TJSONProtocol:JSON格式;
    TSimpleJSONProtocol:提供JSON只写协议, 生成的文件很容易通过脚本语言解析;
    TDebugProtocol:使用易懂的可读的文本格式,以便于debug
    TTransport(传输层),定义数据传输方式,可以为TCP/IP传输,内存共享或者文件共享等)被用作运行时库。

  • TSocket:阻塞式socker;
    TFramedTransport:以frame为单位进行传输,非阻塞式服务中使用;
    TFileTransport:以文件形式进行传输;
    TMemoryTransport:将内存用于I/O,java实现时内部实际使用了简单的ByteArrayOutputStream;
    TZlibTransport:使用zlib进行压缩, 与其他传输方式联合使用,当前无java实现;

  • Thrift支持的服务模型
    TSimpleServer:简单的单线程服务模型,常用于测试;
    TThreadPoolServer:多线程服务模型,使用标准的阻塞式IO;
    TNonblockingServer:多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式);

Thrift实际上是实现了C/S模式,通过代码生成工具将thrift文生成服务器端和客户端代码(可以为不同语言),从而实现服务端和客户端跨语言的支持。用户在Thirft文件中声明自己的服务,这些服务经过编译后会生成相应语言的代码文件,然后客户端调用服务,服务器端提服务便可以了。

【dubbo的实现】
dubbo网络通讯层主要实现了以下功能:

  • 多种网络通讯框架的抽象封装(netty,mina,grizzly)
  • 每个客户端主机和服务端保存单个长链接通信
  • 异步调用转同步
  • tcp链接的心跳和自动重连
  • 基于header头通讯协议,请求的编解码器

dubbo的网络通信基于NIO框架,一般基于事件的NIO网络框架都涉及到 channel , channelHandle核心概念,网络数据buffer, 网络数据编解码器,dubbo为了能够适配多种NIO框架,将以上概念全部又抽象了一层接口。如果有netty开发经验或者了解netty helloworld demo程序对于理解这个章节非常有帮助。
参考链接:
https://www.jianshu.com/p/1e0c8c08e89d
https://www.jianshu.com/p/1a1404ce2201
https://blog.csdn.net/qq418517226/article/details/51906357

4.序列化

  • thrift只支持对thrift协议描述的IDL进行序列化,包含如下几种序列化格式:
    TBinaryProtocol:二进制格式;
    TCompactProtocol:压缩格式;
    TJSONProtocol:JSON格式;
    TSimpleJSONProtocol:提供JSON只写协议, 生成的文件很容易通过脚本语言解析;
    TDebugProtocol:使用易懂的可读的文本格式,以便于debug

  • dubbo支持各种协议的序列化(实际上,dubbo没有IDL这一机制,因为实际上他就是通过java服务对象接口进行交互的) 例如他也可支持thrift协议,只需要thrift将IDL转换为一个java服务对象接口,那么dubbo就可以使用了