讲清楚RPC,从论文开始

648 阅读10分钟

上周有朋友建议π酱出一篇RPC和Http的区别。利用零碎时间大概查阅了一下其他博客和技术信息网站之后,发现好多都是在重复概念性信息,没有讲到本质上。经过大量的信息对比,π酱得到了初步结论。但是整理文章的时候,发现有些信息不全,索性就直接读了RPC的这篇21页的论文。因为不是计算机出身,而且多年没看paper,其中一些翻译可能不是很专业,多担待。
什么是RPC

现在通用的RPC基础原理都是基于这篇1984年 Bruce Jay Nelson的文章,具体实现有所差异。

图片


RPC 中文翻译为「远程过程调用」。根据论文摘要,论文主要描述了如何实现一种用于提供远程程序调用的包。围绕这个中心,论文论述了RPC机制的结构,绑定RPC客户端,RPC相关的信息传输协议,和一些优化
Paper的好处就在于学术界的每句话都是有理有据,不是凭空捏造。论文说,RPC的提出可以上溯到1976年,是另一篇论文提出的,具体是哪篇论文,我们就不详细看了。但是1976年这篇论文大概意思是这样的:

图片

RPC基于这样一个事实:单机上可以实现单个程序的控制和数据处理。那么,在网络架构中,这样的机制(多台机器之间实现程序的控制和数据相关操作)也是可以实现的。当一个远程程序被调用的时候(Java 里面常见的 invoke 是不是出现了),发起调用的这个环境(机器A)会被阻塞,然后相关的参数会通过网络传到另一个需要执行的机器B上去(callee),实际的逻辑处理操作其实是在机器B上执行的。而当机器A上的发起远程调用的程序被阻塞的时候,机器A上的其他程序可能依旧在执行,这取决于机器A环境的并发机制和RPC调用的实现机制。
所以,RPC其实是相对于本地调用来说的,本地调用就是一个机器上的进程内进行逻辑处理(对应代码实现逻辑:接收请求,进行逻辑处理,操作内存和数据库,不管是进程间还是进程内,所有的请求都是在单机上进行的)。而远程调用则是把其中的一部分执行逻辑放在另外一台机器上进行,对于调用方,表面看起来是一样的,但是和本地进程间的操作实际是不一样的。这其实是单机时代向多机器时代发展的开始,因此,好多文章会说RPC用于分布式架构。
RPC优点

图片


论文也提到了RPC的3个优点:(1)有利于分布式计算(2)程序调用更简单快速(3)在单机计算时代,程序往往是算法各个部分沟通的重要机制。π酱强行理解了一下,emmm,没懂。不过,不重要了,刚才我们已经了解了RPC的基本概念,接下来我们看一下这篇论文是怎么实现RPC机制的,也就是文章的开头介绍的论文摘要部分。

RPC结构图

先上一张论文的RPC结构图,是不是看到了技术博客上RPC结构图的影子,一共分为5个部分:客户端(Caller machine User)、客户端Stub ( Caller machine User-stub)、网络传输模块(RpcRuntime)、服务端(Callee machine Server)、服务端Stub(Callee machine Server-stub)。
图片
什么是Stub? 存根的意思。类似银行存根,就是一个记录表。

图片

从结构图可以看出,客户端、客户端Stub 和一个RPCRuntime实例是在客户端机器上的,而服务端、服务端Stub和另一个RPCRuntime实例在服务端机器上。然后当一个用户发起远程调用的时候,会在客户端机器上发起一个本地调用,调起客户端Stub,然后客户端Stub会把本地调用传过来的参数信息打包成一个一个包发送给服务端机器上的RPCRuntime。服务端机器的RPCRuntime收到这些包之后,把他们传递给服务端Stub。然后服务端Stub接收这些包,交给服务端本地执行,对应下图Callee machine 的 work(在这个过程中,客户端处于阻塞状态,对应下图 Caller machine 的 wait )。服务器在本地执行完毕之后,把得到的结果按照原路返回回去(逆流程见下图逆向箭头流),这样就完成了一次RPC调用。

图片user-stub, the RPC communication

在这个过程中RPCRuntime主要负责重播、确认、数据包路由和加密,也就是包级别的信息传输。有没有觉得这里应该和Http有点什么关系?我们先接着把RPC看完,再说Http的事。

现在,我们已经知道了RPC调用的过程和RPCRuntime的作用。其中描述的本地唤起程序什么的都比较好理解,但是2个RPCRuntime实例之间调用是怎么实现的,相互调用走的是什么网络传输协议我们还不明白。带着这2个问题,开始扒下面的论文内容。

RPC调用过程

首先说RPCRuntime实例之间进程调用是怎么实现的? 于是,继续看了一段、两段、三段..... 看不下去了,也没太看懂,大概说说吧。

图片

作者说,RPCRumtime 是Cedar 系统的一个标准部分,Cedar系统是引用的一篇文献中的系统。其中客户端和服务端被记录为分布式系统的一个部分,而客户端Stub和服务端Stub是由一个叫Lupine的程序自动生成的,这个生成算法是由另一个叫Mesa 的接口模块实现的。一个接口模块主要是一系列程序名的列表,包含对应的参数和返回结果(这不就是Java的接口定义么)。这些信息足以让客户端和服务端独立的执行编译时的类型检查和生成适当的调用序列。使用这个接口模块的程序需要引入(import)这个接口,需要实现这个接口模块的程序需要提供(export)这个接口。然后Lupine这个程序会生成Stub, 把服务端提供的接口放在客户端Stub,客户端需要调用的接口放在服务端Stub。这样的话,工程师就无需关注具体的通讯逻辑,只关注业务代码就可以。而Lupine会负责对这些接口的参数和返回结果进行编码、解码以及将客户端发起的请求正确的发送给服务端Stub。

翻译一下,大概的意思就是,有一个中控器,会把服务端提供的接口生成到客户端Stub里面,而客户端要调用的接口也会被存到服务端Stub里面。这样,每次客户端发起请求,这个中控器就会查客户端Stub的小本本,这个应该对应哪个服务端的哪个程序,然后自己完成服务端的调用,服务端收到这个请求之后,从自己的服务端Stub获取到参数本地执行完毕之后,根据Stub的小本本信息,查到是哪个客户端发过来的请求,然后利用中控器把这个响应结果发送回去。而这个RPCRuntime 的中控器是有人已经封装好的,工程师无需重复开发,直接调用即可。

其实从客户端发起一次RPC调用,在客户端业务逻辑处理完毕,真正调用远程服务的时候。在Java里面多数是用AOP切面然后使用动态代理实现的,这里就不展开说了。\

RPC通信协议

既然中控器可以实现网络通信,那么,我们现在看看RPCRuntime包级别的信息传输是怎么回事吧

图片

作者说,其实不需要专门实现特殊的协议来支持RPC,比如文章使用的就是PUP 二进制传输协议。专门查了一下,PUP是1980年IEEE一篇论文提出的一个传输协议。理解一下这句话,意思就是RPC支持任何协议,包括Http。

我们从上面的RPC的传输过程分析一下这是怎么回事。RPCRuntime提供 了一个中控器用来生成客户端和服务端的存根,然后自己做的消息的发送、确认、编码,解码。两边的活儿都是一个中控器在做的,那只要自己能把发送过去的信息解析出来就可以了,什么格式的协议并不重要。

到这里,我们就把RPC的主要原理分析完了,至于细节问题,就不深挖了。

RPC相关问题

我们回到最开始的问题 “RPC 和 Http 有什么区别” ?刚才已经说清楚了。因为最开始做调研信息筛选的时候,网上有些资料还是比较混淆的,接下来π酱补充几个问题。

(1)RPC框架?RPC协议?RPC到底是什么?

框架:是整个或部分系统的可重用设计,表现为一组抽象构建以及构建实例间交互的方法,是为开发者定制的应用框架。网络协议:计算机网络中互相通信的对等实体之间交换信息时所必须遵循的规则的集合。

具体不知道这2个名称是来源于哪里,就调研结果来说,称为RPC框架更合适些。或者,其实RPC是一种架构思想。常见的RPC框架有:Dubbo、gRPC、Spring Boot / Spring Cloud 。常见的协议有?这恐怕分开说了。在网络模型中说协议的时候,要说分层协议,比如:传输层的TCP/UDP、应用层的Http协议等等、以及面向RPC框架出现的远程通信协议,如:RMI 、SOAP 等,是基于基础协议定义的,说起来就比较复杂了。

(2)证明一下我们的思路,可以看Dubbo的配置文件

Dubbo的配置文件里面有protocol(协议)这一配置,常用配置参数有Dubbo、RMI、Hessian、Http、Thrift。是不是可以证明RPC框架里面是可以用Http 协议的,他们的关系仅此而已。其他协议的优劣就不搬运了,大家可以自行查阅。

(3)为什么RPC多用于公司的内部服务之间?

论文也提到了,RPC主要服务于分布式系统调用。除了协议的易用性,个人认为,主要还是框架化、组件化之后,工程师不用每个接口都编写网络调用逻辑,也提到了代码的简洁性,可读性。\

(4)RPC的进程间通信怎么解释?

这个里面的进程其实有点偷换概念了。因为一般学术界提出一种创新思路的时候更希望有论据支撑,更通用化。但是在工程实践上,这确实不是同一个进程,也不是同一台机器的不同进程。当发生网络错误或者丢包的时候,分布式通信的容灾确实比不上单机的进程。

PS: 欢迎讨论和指正错误!!!

转载自公众号[程序媛的被窝]: mp.weixin.qq.com/s?__biz=Mzk…