学习笔记-如何做架构之远程服务调用下-2月day09

文章回顾了RPC框架的历史,从DCE/RPC和ONCRPC开始,讨论了CORBA和WebService的发展及其局限性。现代RPC框架如gRPC和Thrift侧重于性能和简化,而JSON-RPC则以简洁为特点。文章指出,由于功能、简单性和性能之间的权衡,没有一个“完美”的RPC框架,成功的框架往往会在某一方向上做出突出贡献,如面向对象、性能优化或简化使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

深入认识RPC框架。回顾工业界在 RPC 这个领域曾经出现过的各种协议,并了解RPC要解决什么问题,以及如何选择适合自己的 RPC 框架。

在 80 年代中后期,惠普和 Apollo 提出了网络运算架构(Network Computing Architecture,NCA)的设想,并随后在DCE 项目中,发展成了在 Unix 系统下的远程服务调用框架DCE/RPC。

1988 年,Sun Microsystems 起草并向互联网工程任务组(Internet Engineering Task Force,IETF)提交了RFC 1050规范,此规范中设计了一套面向广域网或混合网络环境的、基于 TCP/IP 网络的、支持 C 语言的 RPC 协议,后来也被称为是ONC RPC(Open Network Computing RPC/Sun RPC)。

这两个 RPC 协议,就可以算是如今各种 RPC 协议的鼻祖了。从它们开始,一直到接下来的这几十年,所有流行过的 RPC 协议,都不外乎通过各种手段来解决三个基本问题:

  1. 如何表示数据?
  2. 如何传递数据?
  3. 如何表示方法?

要解决的三个基本问题

表示数据

面临的问题

这里的数据包括了传递给方法的参数,以及方法的返回值。无论是将参数传递给另外一个进程,还是从另外一个进程中取回执行结果,都会涉及应该如何表示的问题。

远程方法调用,还会面临交互双方分属不同程序语言的情况。

即使是只支持同一种语言的 RPC 协议,在不同硬件指令集、不同操作系统下,也完全可能有不一样的表现细节,比如数据宽度、字节序的差异等。

有效的方法

将交互双方涉及的数据,转换为某种事先约定好的中立数据流格式来传输,将数据流转换回不同语言中对应的数据类型来使用,即序列化与反序列化

每种 RPC 协议都有对应的序列化协议:

  • ONC RPC 的External Data Representation (XDR)
  • CORBA 的Common Data Representation(CDR)
  • Java RMI 的Java Object Serialization Stream Protocol
  • gRPC 的Protocol Buffers
  • Web Service 的XML Serialization
  • 众多轻量级 RPC 支持的JSON Serialization

传递数据

具体指如何通过网络,在两个服务 Endpoint 之间相互操作、交换数据。这里“传递数据”通常指的是应用层协议,实际传输一般是基于标准的 TCP、UDP 等传输层协议来完成的。

关键问题是,两个服务交互不是只扔个序列化数据流来表示参数和结果就行了,诸如异常、超时、安全、认证、授权、事务等信息,都可能存在双方交换信息的需求。

有专门的术语来描述,Wire Protocol表示两个 Endpoint 之间交换这类数据的行为,如:

  • Java RMI 的Java Remote Message Protocol(JRMP,也支持RMI-IIOP)
  • CORBA 的Internet Inter ORB Protocol(IIOP,是 GIOP 协议在 IP 协议上的实现版本)
  • DDS 的Real Time Publish Subscribe Protocol(RTPS)
  • Web Service 的Simple Object Access Protocol(SOAP)
  • 如果要求足够简单,双方都是 HTTP Endpoint,直接使用 HTTP 也可以(如 JSON-RPC)

表示方法(服务)

先来回顾本地方法调用,编译器或者解释器会根据语言规范,把调用的方法转换为进程地址空间中方法入口位置的指针。

一个简单的想法是,给程序中的每个方法,都规定一个通用的又绝对不会重复的编号,在调用的时候,直接传这个编号就可以找到对应的方法。(虽然上面的想法不切实际,但是却启发了UUID的使用和流行)

这个问题的关键是设计一套语言无关的接口描述语言(Interface Description Language,IDL),如:

  • Android 的Android Interface Definition Language(AIDL)
  • CORBA 的OMG Interface Definition Language(OMG IDL)
  • Web Service 的Web Service Description Language(WSDL)
  • JSON-RPC 的JSON Web Service Protocol(JSON-WSP)

RPC框架的演进

早期的DCE/RPC 与 ONC RPC框架存在的问题是:

  1. 基于Unix开发,不具有扩展性
  2. 只支持传递值而不支持传递对象(因为它们是面向 C 语言设计的)

CORBA 1.0(Common Object Request Broker Architecture)是对象管理组织(Object Management Group,OMG)在1991年发布的跨进程、面向异构语言的、支持面向对象的服务调用协议。CORBA 3.0 版本已经支持了C、C++、Java、Object Pascal、Python、Ruby等主流和Smalltalk、Lisp、Ada、COBOL等语言。
CORBA的优势很明显:由国际标准组织牵头、由多个软件提供商共同参与。
但它的问题是设计过于啰嗦和繁琐,参考CORBA 的首席科学家 Michi Henning 的文章The Rise and Fall of CORBA;另外随着CORBA 规范的发展,其内容逐渐晦涩难懂(熵增!),各家语言厂商都有自己的解读,导致 CORBA 的实现互不兼容。

接下来,Web Service获得了一统 RPC 的好机会。
1998 年,XML 1.0 发布,并成为了万维网联盟(World Wide Web Consortium,W3C)的推荐标准。1999 年末,以 XML 为基础的 SOAP 1.0(Simple Object Access Protocol)规范的发布,代表着一种被称为“Web Service”的全新 RPC 协议的诞生。
Web Service 是由微软和 DevelopMentor 公司共同起草的远程服务协议,随后被提交给 W3C,并通过投票成为了国际标准。所以,Web Service 也被称为是 W3C Web Service。
Web Service 采用了 XML 作为远程过程调用的序列化、接口描述、服务发现等所有编码的载体(当时XML备受追捧,如同当前的ChatGPT?!)。但从技术角度来看,它设计得也并不优秀,甚至同样可以说是有显著缺陷。
对于开发者而言,Web Service 的一大缺点,就是过于严格的数据和接口定义所带来的性能问题。虽然Web Service 吸取了 CORBA 的教训,不再需要程序员手工去编写对象的描述和服务代理,但是 XML 作为一门描述性语言,本身的信息密度就很低(都不用与二进制协议比,与今天的 JSON 或 YAML 比一下就知道了)。同时,Web Service 是一个跨语言的 RPC 协议,这使得一个简单的字段,为了在不同语言中不会产生歧义,要以 XML 描述去清楚的话,往往比原本存储这个字段值的空间多出十几倍、几十倍乃至上百倍
这个特点就导致了,要想使用 Web Service,就必须要有专门的客户端去调用和解析 SOAP 内容,也需要专门的服务去部署(如 Java 中的 Apache Axis/CXF);更关键的是,这导致了每一次数据交互都包含大量的冗余信息,性能非常差。
Web Service想通过一套协议,一揽子解决分布式计算中可能遇到的所有问题,也使其自身变得复杂(少年终将称为恶龙?!),Web Service 协议家族中,除它本身包括了的 SOAP、WSDL、UDDI 协议之外,还有一堆以WS-*命名的子功能协议,来解决事务、一致性、事件、通知、业务描述、安全、防重放等问题。

总结一下RPC的发展,面向透明的、简单的 RPC 协议,如 DCE/RPC、DCOM、Java RMI,要么依赖于操作系统,要么依赖于特定语言,总有一些先天约束;那些面向通用的、普适的 RPC 协议,如 CORBA,就无法逃过使用复杂性的困扰;而那些意图通过技术手段来屏蔽复杂性的 RPC 协议,如 Web Service,又不免受到性能问题的束缚。
简单、普适和高性能,似乎真的难以同时满足。

RPC框架的现状

由于一直没有一个能同时满足以上简单、普适和高性能的“完美 RPC 协议”,相继出现许多框架:
RMI(Sun/Oracle)、Thrift(Facebook/Apache)、Dubbo(阿里巴巴 /Apache)、gRPC(Google)、Motan2(新浪)、Finagle(Twitter)、brpc(百度)、.NET Remoting(微软)、Arvo(Hadoop)、JSON-RPC 2.0(公开规范,JSON-RPC 工作组)……

这些 RPC 的功能、特点都不太一样,有的是某种语言私有,有的能支持跨越多门语言,有的运行在 HTTP 协议之上,有的能直接运行于 TCP/UDP 之上,但没有哪一款是“最完美的 RPC”。据此,我们也可以发现一个规律,任何一款具有生命力的 RPC 框架,都不再去追求大而全的“完美”,而是会找到一个独特的点作为主要的发展方向。(就如同当前的世界,没有一超,只有多强)
几个典型的发展方向:

  • 朝着面向对象发展。这条线的缘由在于,在分布式系统中,开发者们不再满足于 RPC 带来的面向过程的编码方式,而是希望能够进行跨进程的面向对象编程。因此,这条线还有一个别名叫作分布式对象(Distributed Object),它的代表有 RMI、.NET Remoting。当然了,之前的 CORBA 和 DCOM 也可以归入这一类。
  • 朝着性能发展,代表为 gRPC 和 Thrift。决定 RPC 性能主要就两个因素:序列化效率和信息密度。序列化效率很好理解,序列化输出结果的容量越小,速度越快,效率自然越高;信息密度则取决于协议中,有效荷载(Payload)所占总传输数据的比例大小,使用传输协议的层次越高,信息密度就越低,SOAP 使用 XML 拙劣的性能表现就是前车之鉴。gRPC 和 Thrift 都有自己优秀的专有序列化器,而在传输协议方面,gRPC 是基于 HTTP/2 的,支持多路复用和 Header 压缩,Thrift 则直接基于传输层的 TCP 协议来实现,省去了额外的应用层协议的开销。
  • 朝着简化发展,代表为 JSON-RPC。要是说选出功能最强、速度最快的 RPC 可能会有争议,但要选出哪个功能弱的、速度慢的,JSON-RPC 肯定会是候选人之一。它牺牲了功能和效率,换来的是协议的简单。也就是说,JSON-RPC 的接口与格式的通用性很好,尤其适合用在 Web 浏览器这类一般不会有额外协议、客户端支持的应用场合。(这说的难道不是JS?!)

经历了 RPC 框架的“战国时代”,开发者们终于认可了,不同的 RPC 框架所提供的不同特性或多或少是互相矛盾的,很难有某一种框架说“我全部都要”。要把面向对象那套全搬过来,就注定不会太简单(比如建 Stub、Skeleton 就很烦了,即使由 IDL 生成也很麻烦);功能多起来,协议就要弄得复杂,效率一般就会受影响;要简单易用,那很多事情就必须遵循约定而不是配置才行;要重视效率,那就需要采用二进制的序列化器和较底层的传输协议,支持的语言范围容易受限。

而到了最近几年,RPC 框架有明显朝着更高层次(不仅仅负责调用远程服务,还管理远程服务)与插件化方向发展的趋势,不再选择自己去解决表示数据、传递数据和表示方法这三个问题,而是将全部或者一部分问题设计为扩展点,实现核心能力的可配置,再辅以外围功能,如负载均衡、服务注册、可观察性等方面的支持。这一类框架的代表,有 Facebook 的 Thrift 和阿里的 Dubbo(现在两者都是 Apache 的)。

尤其是断更多年后重启的 Dubbo 表现得更为明显,它默认有自己的传输协议(Dubbo 协议),同时也支持其他协议,它默认采用 Hessian 2 作为序列化器,如果你有 JSON 的需求,可以替换为 Fastjson;如果你对性能有更高的需求,可以替换为Kryo、FST、Protocol Buffers 等;如果你不想依赖其他包,直接使用 JDK 自带的序列化器也可以。这种设计,就在一定程度上缓解了 RPC 框架必须取舍,难以完美的缺憾。

总结

RPC 协议 / 框架无法统一的一点是,简单的框架很难能达到功能强大的要求。

功能强大的框架往往要在传输中加入额外的负载和控制措施,导致传输性能降低,而如果既想要高性能,又想要强功能,这就必然要依赖大量的技巧去实现,进而也就导致了框架会变得过于复杂,这就决定了不可能有一个“完美”的框架同时满足简单、普适和高性能这三个要求。

认识到这一点后,一个 RPC 框架要想取得成功,就要选择一个发展方向,能够非常好地满足某一方面的需求。因此,我们也就有了朝着面向对象发展、朝着性能发展和朝着简化发展这三条线。

此文章为2月Day8学习笔记,内容来源于极客时间《周志明的软件架构课

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值