我们知道RPC的目的就是让Client像本地方法一样去调用远程(即Server)服务,而完成这一功能,从上至下,Server需要完成方法的包装序列化,以及负责实现网络通信和方法的具体实现;同样Client调用,首先也得持有方法对象,然后将方法以及参数序列化后,和Server通信,交由Server具体实现,最后Server返回响应的结果。
总结一下,RPC框架需要解决的问题:1. 网络通信 2. 序列化/反序列化 3. 透明化服务调用。下面一一分析。
这也是RPC最直接的目的,Client需要像调用本地方法一样调用Server端的方法,所以在Client和Server端中间必须有一个虚拟桥梁,那就是对象方法服务接口,所以Client和Server都需要持有这个对象方法服务接口。一般而言,都是Server端定义好了对象方法接口,并负责具体的实现,然后将对象方法接口告知Client,然后Client也需要在本地创建一个对象方法接口,并不需要具体实现。这样Client就可以调用接口方法,然后由RPC框架负责序列化参数,并交由服务端的具体实现来完成。
对于不同的框架而言,实现方式有点不同:
【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网络通讯层主要实现了以下功能:
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
thrift只支持对thrift协议描述的IDL进行序列化,包含如下几种序列化格式:
TBinaryProtocol:二进制格式;
TCompactProtocol:压缩格式;
TJSONProtocol:JSON格式;
TSimpleJSONProtocol:提供JSON只写协议, 生成的文件很容易通过脚本语言解析;
TDebugProtocol:使用易懂的可读的文本格式,以便于debug
dubbo支持各种协议的序列化(实际上,dubbo没有IDL这一机制,因为实际上他就是通过java服务对象接口进行交互的) 例如他也可支持thrift协议,只需要thrift将IDL转换为一个java服务对象接口,那么dubbo就可以使用了