远程过程调用(RPC)范式的出现可以追溯到40年之前。时至今日,它仍是在编写分布式应用时使用率最高的一种编程模型。只是近些年来,人们对于RPC技术的质疑与批评声逐渐多了起来。Steve Vinoski在2008年曾尖锐地指出,之所以RPC仍然能够得到诸多开发者的支持,其原因只有一个:舒适感!Vinoski完全不认可这种思想,他表示:
“开发者的舒适感真的比正确性、可伸缩性、性能、关注分离、可扩展性以及附加的复杂性还要重要吗?”
尽管面临着这些尖锐的批评,但RPC的历史地位是不容置疑的,而它在现代化的应用中仍能够占据一席之地,成为分布式计算中一种重要的编程模型。正在攻读博士学位的Christopher Meiklejohn近来开设了一系列博客文章以回顾分布式计算中的各种编程模型与语言,在其中一篇文章中对RPC进行了详尽的回顾与展望。
概述
简单来说,一台机器上的程序对另一台机器上的子程序的调用就是一次RPC调用。在调用过程中,主程序不需要操心与远程执行相关的任何代码,与本地调用相比,其唯一区别就在于需要提供远程节点的标识。最早为人所知并接受的RPC实现是由Sun提供的SunRPC机制,使用在其网络文件系统(NFS)中。
除此之外,常见的RPC机制还包括Java的RMI、DCOM、XML-RPC、SOAP、CORBA,以及Google的gRPC等等。
RPC的早期发展
RPC思想最早的原型可追溯至1974年所发布的RFC 674草案 —— “过程调用协议文档第2版”,该草案当时的目标是为因特网上的全部70个节点定义一种共享资源的通用方式,在该草案中引入了过程调用范围第2版(PCP)的概念。而在第二年发布的RFC 684草案 —— “对以过程调用作为网络协议的评论”中,首次分析了RPC这种编程范式存在的三大问题以及这些问题与分布式系统的本质问题之间的关联。这三大问题可以简要地概述如下:
过程调用通常是一种命令式操作,而命令式操作通常是一种来自底层抽象的非常快速的上下文切换操作。
本地调用与远程调用的不同之处在于:远程调用可能会产生延迟,甚至在产生故障时可能永远也不会返回.
异步的消息传递,或是发送某个消息并等待响应是一种更理想的模型,因为这会使消息的传递变得更加明确。
伴随着这三大问题的是使用这种编程范式时的一系列麻烦,这些麻烦在RPC的40多年发展历史中始终阴魂不散,包括:如何从故障或错误中恢复;如何始终保证操作的正确顺序;RPC范式强制使用者进行同步编程方式;RPC的调用-响应模型使得因系统过载而导致消息无法正常处理时,对优先级的排列变得相当困难。
随后发布的RFC 707草案继承了RFC 684的思想,并提出了一个新问题,即各种服务,例如TELNET与FTP之间的资源共享问题。因为这些服务各自具有不同的接口,因此使用者必须了解他们的操作端口与命令。该草案的作者提出了一个建议:为远程过程的执行定义一个通用的接口,该接口接受一个参数列表,并依然遵循RPC的调用-响应模型。虽然这一提议并未解决RPC 684中所提出的问题,但这一模型在之后依然得到了许多系统的采纳。
CORBA
CORBA是对面向对象语言的一种抽象,允许开发者进行跨机器、跨语言的通信。CORBA通过接口定义语言(IDL)指定远程对象的接口。IDL用于生成远程系统中的对象接口在本机中的桩代码,并且在实际的语言实现与抽象接口之间生成映射关系。
CORBA的试图为应用开发者带来几点益处:不依赖于具体的语言、操作系统以及架构;将IDL中的抽象类型映射为具体实现所带来的静态类型特性;以及对象在不同机器之间的传输。CORBA承诺,通过使用映射,远程方法调用的使用就与本地调用一样简单,甚至与分布式系统相关的异步也可被映射为本地异常进行处理。
但是,Vinoski在2003年表示,仅基于透明性这一点对于编程语言与抽象进行评估的方式是有缺陷的。在他看来,IDL映射的目的在于将中间件抽象直接合并至编程语言的领域中,通过这种透明性减少编程语言与中间件这两者之间的阻抗失调。但问题在于,不恰当的透明性可能会掩盖分布式计算中出现的某些问题,例如并发与部分失败相关的问题。
对RPC范式的批评