2.1.4 统一的RPC
虽然DCE/RPC与ONC RPC都有很浓厚的UNIX痕迹,但是它们并没有真正在UNIX系统以外大规模流行过,而且它们还有一个“大问题”:只支持传递值而不支持传递对象。尽管ONC RPC的XDR的序列化器能用于序列化结构体,但结构体毕竟不是对象,这两种RPC协议都是面向C语言设计的,根本就没有对象的概念。然而20世纪90年代正好又是面向对象编程(Object-Oriented Programming,OOP)风头正盛的年代,所以在1991年,对象管理组织(Object Management Group,OMG)发布了跨进程的、面向异构语言的、支持面向对象的服务调用协议:CORBA 1.0(Common Object Request Broker Architecture)。CORBA的1.0和1.1版本只提供了C、C++语言的支持,到了末代的CORBA 3.0版本,不仅支持C、C++、Java、Object Pascal、Python、Ruby等多种主流编程语言,还支持Lisp、Smalltalk、Ada、COBOL等非主流语言,阵营不可谓不强大。CORBA是一套由国际标准组织牵头,由多家软件提供商共同参与制定的分布式规范,论影响力,当时只有微软私有的DCOM能够与之稍微抗衡,但微软的DCOM与DCE一样,是受限于操作系统的(尽管DCOM比DCE更强大些,能跨多语言),所以同时支持跨系统、跨语言的CORBA原本是最有机会统一RPC这个领域的有力竞争者。
但无奈CORBA本身设计得实在太过于烦琐,甚至有些规定简直到了荒谬的程度——写一个对象请求代理(ORB,这是CORBA中的核心概念)大概要200行代码,其中大概有170行都是纯粹无用的废话——这句话是CORBA的首席科学家Michi Henning在文章“The Rise and Fall of CORBA”[1]中提出的愤怒批评。另一方面,为CORBA制定规范的专家逐渐脱离实际,使得CORBA规范晦涩难懂,各家语言的厂商都有自己的解读,导致CORBA实现互不兼容,实在是对CORBA号称支持众多异构语言的莫大讽刺。这也间接导致稍后W3C Web Service出现后,CORBA与Web Service竞争时犹如十八路诸侯讨伐董卓,互乱阵脚,一触即溃,最终惨败。CORBA的最终归宿是与DCOM一同被扫进计算机历史的博物馆中。
CORBA没有把握住统一RPC的大好时机,很快另外一个更有希望的机会降临。1998年,XML 1.0发布,并成为万维网联盟(World Wide Web Consortium,W3C)的推荐标准。1999年末,SOAP 1.0(Simple Object Access Protocol)规范的发布,标志着一种被称为“Web Service”的全新的RPC协议的诞生。Web Service是由微软和DevelopMentor公司共同起草的远程服务协议,随后提交给W3C投票成为国际标准,所以Web Service也被称为W3C Web Service。Web Service采用XML作为远程过程调用的序列化、接口描述、服务发现等所有编码的载体,当时XML是计算机工业最新的银弹,只要是定义为XML的东西几乎都被认为是好的,风头一时无两,连微软自己都主动宣布放弃DCOM,迅速转投Web Service的怀抱。
交给W3C管理后,Web Service再没有天生属于哪家公司的烙印,商业运作非常成功,大量的厂商都想分一杯羹。但从技术角度来看,它设计得并不优秀,甚至同样可以说是有显著缺陷的。对于开发者而言,Web Service的一大缺点是它过于严格的数据和接口定义所带来的性能问题,尽管Web Service吸取了CORBA失败的教训,不需要程序员手工编写对象的描述和服务代理,可是,XML作为一门描述性语言本身信息密度就相对低下,(都不用与二进制协议比,与今天的JSON或YAML比一下就知道了。)Web Service又是跨语言的RPC协议,这使得一个简单的字段,为了在不同语言中不会产生歧义,要以XML严谨描述的话,往往需要比原本存储这个字段值多出十几倍、几十倍乃至上百倍的空间。这个特点一方面导致了使用Web Service必须要专门的客户端去调用和解析SOAP内容,也需要专门的服务去部署(如Java中的Apache Axis/CXF),更关键的是导致了每一次数据交互都包含大量的冗余信息,性能奇差。
如果只是需要客户端,传输性能差也就算了,又不是不能用。既然选择了XML,获得自描述能力,本来就没有打算把性能放到第一位,但Web Service还有另外一个缺点:贪婪。“贪婪”是指它希望在一套协议上一揽子解决分布式计算中可能遇到的所有问题,这促使Web Service生出了整个家族的协议——去网上搜索一下就知道这句话不是拟人修辞[2]。Web Service协议家族中,除它本身包括的SOAP、WSDL、UDDI协议外,还有一堆数不清的,以WS-*命名的,用于解决事务、一致性、事件、通知、业务描述、安全、防重放等子功能的协议,让开发者学习负担沉重。
当程序员们对Web Service的热情迅速兴起,又逐渐冷却之后,自己也不禁开始反思:那些面向透明的、简单的RPC协议,如DCE/RPC、DCOM、Java RMI,要么依赖于操作系统,要么依赖于特定语言,总有一些先天约束;那些面向通用的、普适的RPC协议,如CORBA,就无法逃过使用复杂性的困扰,CORBA烦琐的OMG IDL、ORB都是很好的佐证;而那些意图通过技术手段来屏蔽复杂性的RPC协议,如Web Service,又不免受到性能问题的束缚。简单、普适、高性能这三点,似乎真的很难同时满足。
[1] 下载地址:https://dl.acm.org/doi/pdf/10.1145/1142031.1142044。
[2] 维基百科中收录了部分WS-*的子协议:https://en.wikipedia.org/wiki/List_of_web_service_specifications。