1996年,美国国防部高级研究计划管理局(ARPA全称:Advanced Research Projects Agency)开始建立一个命名为ARPAnet的网络。最开始只有4个结点,分别是洛杉矶的加利福尼亚州大学洛杉矶分校、加州大学圣巴巴拉分校、斯坦福大学、犹他州大学四所大学的4台大型计算机。选择这四个节点的一个原因是要测试不同类型主机联网的兼容性。
过程调用最早可以追溯到 Jon Postel 和 Jim White 在1974 年发表的 Procedure Call Protocol Documents Version 2(RFC674)。这个协议试图定义一种通用的方法,用于解决 NSW 项目中多个计算节点通信的问题。
协议发表后,引起了非常大的争议,1975年,RFC674的注释篇RFC684 发布。
RFC 684 不是一个独立的协议, 主要对 RFC674 的争议进行讨论。
RPC 是远程过程调用(Remote Procedure Call)的缩写形式,Birrell 和 Nelson 在 1984 发表于 ACM Transactions on Computer Systems 的论文《Implementing remote procedure calls》对 RPC 做了经典的诠释。RPC 是指计算机 A 上的进程,调用另外一台计算机 B 上的进程,其中 A 上的调用进程被挂起,而 B 上的被调用进程开始执行,当值返回给 A 时,A 进程继续执行。调用方可以通过使用参数将信息传送给被调用方,而后可以通过传回的结果得到信息。而这一过程,对于开发人员来说是透明的。之后的几年RPC一直被认为是建立分布式操作系统的最合适的范式。
1987年,Tanenbaum 和 Renesse发表文章《A Critique of the Remote Procedure Call Paradigm》,讨论了RPC 模型的概念问题、实现技术问题、客户端和服务端崩溃后的处理问题、不同系统间的问题以及性能等多方面的问题,并对存在的问题进行了分析。
Sun 公司是第一个提供商业化 RPC 库和 RPC 编译器。在1980年代中期, Sun 计算机提供 RPC,并在 Sun Network File System(NFS) 得到支持。该协议被主要以 Sun 和 AT&T 为首的 Open Network Computing (开放网络计算)作为一个标准来推动。这是一个非常轻量级 RPC 系统,可用在大多数 POSIX 和类 POSIX 操作系统中使用,包括 Linux、SunOS、OS X 和各种发布版本的 BSD。这样的系统被称为 Sun RPC 或 ONC RPC。最终sun成功了,sunrpc 成了第一个rpc的标准。
1989年,蒂姆·伯纳斯-李发明了万维网。第二年9月,开发了第一个网页浏览器。到1990年圣诞节,蒂姆·伯纳斯-李创建运行万维网所需的所有工具:超文本传输协议(HTTP)、超文本标记语言(HTML)、第一个网页浏览器、第一个网页服务器和第一个网站,实现了超文本传输协议客户端与服务器的第一次通讯。他也因此而获得了2016年的图灵奖。到1995年,互联网在美国已完全商业化。
OMG成立于1989年,作为一个非营利性组织,集中致力于开发在技术上具有先进性、在商业上具有可行性并且独立于厂商的软件互联规范,推广面向对象模型技术,增强软件的可移植性(Portability)、可重用性(Reusability)和互操作性(Interoperability)。CORBA 试图为应用程序开发人员提供几个好处: 语言独立性、操作系统独立性、体系结构独立性、通过 IDL 中的抽象类型映射到这些类型的机器和语言特定实现的静态类型,以及对象传输,其中对象可以通过不同机器之间的连接进行迁移。
Jim Waldo 等人发表了一篇 名为 《A Note on Distributed Computing》的论文。 这篇论文详细讨论了为什么 RPC 模型扩展到对象,是有问题的。作者认为,远程计算的问题主要有通信时延、地址空间隔离、局部故障、并发问题。
1996 年,HTTP/1.0 版本发布,大大丰富了 HTTP 的传输内容,除了文字,还可以发送图片、视频等,这为互联网的发展奠定了基础。在 HTTP/1.0 发布几个月后,HTTP/1.1 就发布了。HTTP/1.1 更多的是作为对 HTTP/1.0 的完善。
1994年12月,CORBA 2.0 就已经发布规范,该规范希望能够解决不同厂商根据COBRA规范所开发的产品“互联互不通”的严重问题,但直到1997年,Corba2.0 才正式发布,但是最后还是失败了。至于COBRA失败的原因,COBRA阵营的技术大牛、COBRA技术的推动者,即后来加入反COBRA阵营的Michi Henning,在他的《The rise and fall of CORBA》书里做了如下深刻的总结。规范巨大而复杂、CORBA学习曲线陡峭、编程开发过于复杂、费用昂贵、Sun与Java成为COBRA最大的竞争对手【转向Web】、XML技术的兴起加速了COBRA的没落。
最初参与CORBA 的一批技术专家不满CORBA 的设计,另起炉灶打造了新的RPC—即 ZeroC Ice,ICE 最初的广告语为“反叛之冰”。它也一直延续至今,发展成了一个强大的微服务架构平台。
1998 年 XML 1.0 发布,被 W3C (World Wide Web Consortium) 推荐为标准的描述语言。同年,微软和DevelopMentor发布SOAP(Simple Object Access Protocol),随后提交给W3C作为标准。SOAP是一个严格定义的信息交换协议,使用XML作为RPC新的对象序列化机制,用于在Web Service中把远程调用和返回封装成机器可读的格式化数据。
2000年,Roy Thomas Fielding 博士在他的博士论文 《Architectural Styles and the Design of Network-based Software Architectures》首次提出了 REST 这个词。
REST提供了一系列架构约束,当作为整体使用时,它强调组件交互的可扩展性、接口的通用性、组件的独立部署,以及那些能减少交互延迟的中间件,它强化了安全性,也能封装遗留系统。
为什么学习曲线陡峭、设计复杂的Rust 是程序员的最爱?
为什么易学易用但有各种语言缺陷的JavaScript 能成为最流行的语言呢?
开发者的便利性比正确性、可扩展性、性能、关注点分离、可扩展性和偶然复杂度更重要。
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
Thrift 是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。
Thrift 和 Protocol Buffer 不同,它不仅仅是一个数据序列化工具,而是一个完整的RPC 框架。另一个不同点在于,Protobuf 标准化了单一的二进制编码方式,但Thrift 则包含了多种不同的序列化方式(Thirft 称之为协议)。
Avro 是一个基于二进制数据传输高性能的中间件,在2009年成为 Hadoop 中的一个子项目,并与2015年脱离Hadoop,加入Apache成为一个独立的项目。Avro 同样支持跨编程语言实现(C, C++, C#,Java, Python, Ruby, PHP),Avro 提供着与诸如 Thrift 和 Protocol Buffers 等系统相似的功能。
在 2010 年到 2015 年,谷歌通过实践一个实验性的 SPDY 协议,证明了一个在客户端和服务器端交换数据的另类方式。其收集了浏览器和服务器端的开发者的焦点问题,明确了响应数量的增加和解决复杂的数据传输。SPDY 最终进化成了HTTP2.0 并于2015年发布。使用二进制分帧层、多路复用、数据流优先级、服务端推送、头部压缩。
2015 年,Google 将gRPC框架开源,gRPC 使用 PB 作为序列化的解决方案,而在传输的介质上使用了 HTTP/2而不是常见的TCP。gRPC 是一个多路复用、双向流式 RPC 协议。在一般的 RPC 机制中,客户端发起到服务器的连接,只有客户端可以请求,而服务器只能响应传入的请求。然而,在双向 gRPC 流中,虽然初始连接是由客户端发起的(称为端点1) ,但是一旦建立连接,服务器(称为端点2)和端点1都可以发送请求和接收响应。这极大地简化了两个端点相互通信的开发(如网格计算)。由于两个数据流都是独立的,这也省去了在端点之间创建两个独立连接的麻烦(一个从端点1到端点2,另一个从端点2到端点1)。
管道类似于两个进程间的桥梁,可通过管道在进程间传递少量的字符流或字节流。普通管道只用于有亲缘关系进程(由一个进程启动的另外一个进程)间的通信,具名管道摆脱了普通管道没有名字的限制,除具有管道所有的功能外,它还允许无亲缘关系进程间的通信。管道典型的应用就是命令行中的|操作符,譬如:
ps -ef | grep C++
信号用于通知目标进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程自身。信号的典型应用是kill命令,譬如:
kill -9 pid
信号量用于两个进程之间同步协作手段,它相当于操作系统提供的一个特殊变量,程序可以在上面进行wait()和notify()操作。
以上三种方式只适合传递传递少量信息,POSIX 标准中定义了消息队列用于进程间数据量较多的通信。进程可以向队列添加消息,被赋予读权限的进程则可以从队列消费消息。消息队列克服了信号承载信息量少,管道只能用于无格式字节流以及缓冲区大小受限等缺点,但实时性相对受限。
允许多个进程访问同一块公共的内存空间,这是效率最高的进程间通信形式。原本每个进程的内存地址空间都是相互隔离的,但操作系统提供了让进程主动创建、映射、分离、控制某一块内存的程序接口。当一块内存被多进程共享时,各个进程往往会与其它通信机制,譬如信号量结合使用,来达到进程间同步及互斥的协调操作。
消息队列和共享内存只适合单机多进程间的通信,套接字接口是更为普适的进程间通信机制,可用于不同机器之间的进程通信。套接字(Socket)起初是由 UNIX 系统的 BSD 分支开发出来的,现在已经移植到所有主流的操作系统上。出于效率考虑,当仅限于本机进程间通信时,套接字接口是被优化过的,不会经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等操作,只是简单地将应用层数据从一个进程拷贝到另一个进程,这种进程间通信方式有个专名的名称:UNIX Domain Socket,又叫做 IPC Socket。
1987 年,在“透明的 RPC 调用”一度成为主流范式的时候,Andrew Tanenbaum 教授曾发表了论文《A Critique of The Remote Procedure Call Paradigm》,对这种透明的 RPC 范式提出了一系列质问:
多年发展逐渐证明 Andrew Tanenbaum 的预言是正确的。最终,到 1994 年至 1997 年间,由 ACM 和 Sun 院士Peter Deutsch、套接字接口发明者Bill Joy、Java 之父James Gosling等一众在 Sun Microsystems 工作的大佬们共同总结了通过网络进行分布式运算的八宗罪(8 Fallacies of Distributed Computing):
C/S架构间,自定义协议,例如 TLV(Type-Length-Value),两侧需要对照报文进行序列化和反序列化。该模式比较常用,一些轻框架的小应用,这么用程序小,效率高。
不过需要自己解决粘包拆包,线程池优化,大文件传输等问题。
TLV: TLV是指由数据的类型Tag,数据的长度Length,数据的值Value组成的结构体,几乎可以描任意数据类型,TLV的Value也可以是一个TLV结构,正因为这种嵌套的特性,可以让我们用来包装协议的实现。
COM(组件对象模型,Component Object Model)技术的目标是让使用不同语言编写、运行在不同进程甚至不同计算机中的程序可以通过组件对象模型来进行统一建模,使得不同程序之间可以用同样的方式来调用彼此。
后来逐步迭代到COM+、DCOM。
微软提出的 COM 最后因为过度抽象并没有大范围应用。
CORBA,Common Object Request Broker Architecture,公共对象请求代理体系结构。由OMG组织制订的一种标准的面向对象应用程序体系规范。或者说 CORBA体系结构是OMG为解决分布式处理环境(DCE)中,硬件和软件系统的互连而提出的一种解决方案。
现在CORBA用的已经很少了,基本上只有一些大的电信项目还在用,现在同类的解决方案中WebService是比较流行的。
《The Rise and Fall of CORBA》一文中,比较详细的介绍了为什么CORBA会衰落。总结起来有几点:
XML-RPC发表于1998年,由UserLand Software(UserLand Software)的Dave Winer及Microsoft共同发表。后来在新的功能不断被引入下,这个标准慢慢演变成为今日的SOAP协议。
SOAP能够在企业级软件开发中生存很久,很重要的一个原因是,大家在工作中用到的OA系统、报表工具、CRM系统等,即使慢如蜗牛,大家也不会太多抱怨,趁着网页卡在那里的时间,正好喝喝茶,聊聊天;而CTO们更不会有抱怨了,因为他们只负责买,又不负责用。
ESB(企业服务总线)借着SOA概念的流行,在2000年之后快速兴起。
ESB的初衷是好的,它希望能够在SOAP的基础上,解决其只能点对点路由的问题,同时还可以兼容不同通信协议。但是,为了解决一个问题,它引入了另一个问题,就是业务逻辑与ESB绑定,导致ESB变得越来越不“单纯”,最后ESB越来越大,越来越复杂,越来越难以维护,最后就成了整个系统的痼疾。
WCF是微软在实现大一统梦想的路上,推出的又一力作。WCF继承了COM的衣钵,希望以一种统一的方式,将TCP通信、HTTP服务、SOAP服务、REST服务等等,都封装起来,在开发者看来,都是一个本地方法调用。
REST(Representational State Transfer,表述性状态转移)是当今最为流行的API。因为大量的Web应用采用REST作为其API的选择。REST是Roy Thomas Fielding博士于2000年在他的博士论文中提出来的一种万维网软件架构风格。
SOAP仅仅将HTTP作为一种可选的数据传输方式,REST则是带着HTTP基因出生的。首先,REST将服务间通信进行了一次抽象,所有的服务交互都建模成对资源的CRUD操作;其次,它充分利用了HTTP协议中丰富的动词,遵循约定大于配置的互联网开发哲学,避免了复杂和冗余的方法定义;再次,由于通过HTTP的动词可以明确区分读写操作,对于GET类的读操作,还可以通过缓存或者CDN进行加速;最后,采用JSON或者XML等通用格式来描述数据,简单,直接。基于这几点,REST开始在互联网领域大行其道。
如果选功能弱的、速度慢的,JSON-RPC 肯定会候选人中之一。牺牲了功能和效率,换来的是协议的简单轻便,接口与格式都更为通用,尤其适合用于 Web 浏览器这类一般不会有额外协议支持、额外客户端支持的应用场合。
1、wiki–Remote procedure call
2、编程十年之那些年我见过和用过的RPC
3、序列化与反序列化深入理解
4、OMG–IDL(Interface Definition Language)
5、软件架构–服务架构演进
6、远程服务调用
7、RPC 发展史
8、那些年,我们追过的RPC