> 文章列表 > 分布式系统之间的调用——PRC

分布式系统之间的调用——PRC

分布式系统之间的调用——PRC

你所知道的 RPC
说到 RPC(Remote Procedure Call,远程过程调用),你不会陌生,它指的是通过网络,调用另一台计算机上部署服务的技术。
而 RPC 框架就封装了网络调用的细节,让你像调用本地服务一样,调用远程部署的服务。
你也许觉得只有像 Dubbo、Grpc、Thrift 这些新兴的框架才算是 RPC 框架,其实严格来说,你很早之前就接触到与 RPC 相关的技术了。
比如,Java 原生就有一套远程调用框架叫做 RMI(Remote Method Invocation), 它可以让 Java 程序通过网络,调用另一台机器上的 Java 对象的方法。
它是一种远程调用的
方法,也是 J2EE 时代大名鼎鼎的 EJB 的实现基础。
时至今日,你仍然可以通过 Spring 的“RmiServiceExporter”将 Spring 管理的 bean 暴露成一个 RMI 的服务,从而继续使用 RMI 来实现跨进程的方法调用。之所以 RMI 没有像Dubbo,Grpc 一样大火,是因为它存在着一些缺陷:

RMI 使用专为 Java 远程对象定制的协议 JRMP(Java Remote Messaging Protocol)
进行通信,这限制了它的通信双方,只能是 Java 语言的程序,无法实现跨语言通信;
RMI 使用 Java 原生的对象序列化方式,生成的字节数组空间较大,效率很差。
另一个你可能听过的技术是 Web Service,它也可以认为是 RPC 的一种实现方式。它的
优势是,使用 HTTP+SOAP 协议,保证了调用可以跨语言,跨平台。只要你支持 HTTP 协
议,可以解析 XML,那么就能够使用 Web Service。在我来看,它由于使用 XML 封装数
据,数据包大,性能还是比较差。借上面几个例子,我主要是想告诉你,RPC 并不是互联网时代的产物,也不是服务化之后才衍生出来的技术,而是一种规范,只要是封装了网络调用的细节,能够实现远程调用其他服务,就可以算作是一种 RPC 技术了。

PRC调用过程做了什么事情?
在一次 RPC 调用过程中,客户端首先会将调用的类名、方法名、参数名、参数值等信息,序列化成二进制流;
然后客户端将二进制流,通过网络发送给服务端;
服务端接收到二进制流之后,将它反序列化,得到需要调用的类名、方法名、参数名和参数值,再通过动态代理的方式,调用对应的方法得到返回值;
服务端将返回值序列化,再通过网络发送给客户端;
客户端对结果反序列化之后,就可以得到调用的结果了。
分布式系统之间的调用——PRC

从这张图中你可以看到,有网络传输的过程,也有将请求序列化和反序列化的过程, 所以,如果要提升 RPC 框架的性能,需要从网络传输和序列化两方面来优化。

如何提升网络传输性能
在网络传输优化中,你首要做的,是选择一种高性能的 I/O 模型。所谓 I/O 模型,就是我们处理 I/O 的方式。而一般单次 I/O 请求会分为两个阶段,每个阶段对于 I/O 的处理方式是不同的。
首先,I/O 会经历一个等待资源的阶段,比方说,等待网络传输数据可用,在这个过程中我们对 I/O 会有两种处理方式:
阻塞。指的是在数据不可用时,I/O 请求一直阻塞,直到数据返回;
非阻塞。指的是数据不可用时,I/O 请求立即返回,直到被通知资源可用为止。

然后是使用资源的阶段,比如说从网络上接收到数据,并且拷贝到应用程序的缓冲区里面。
在这个阶段我们也会有两种处理方式:
同步处理。指的是 I/O 请求在读取或者写入数据时会阻塞,直到读取或者写入数据完成;
异步处理。指的是 I/O 请求在读取或者写入数据时立即返回,当操作系统处理完成 I/O请求,并且将数据拷贝到用户提供的缓冲区后,再通知应用 I/O 请求执行完成。

将这两个阶段的四种处理方式,做一些排列组合,再做一些补充,就得到了我们常见的五种
I/O 模型:
同步阻塞 I/O
同步非阻塞 I/O
同步多路 I/O 复用
信号驱动 I/O
异步 I/O

有空的时候可以阅读一些成熟的 RPC 框架的源代码。比如,阿里开源的 Dubbo,微博的 Motan 等等,理解它们的实现原理和细节,这样你会更有信心维护好你的微服务系统;同时,你也可以从优秀的代码中,学习到代码设计的技巧,比如说Dubbo 对于 RPC 的抽象,SPI 扩展点的设计,这样可以有助你提升代码能力。