1、RPC简介
RPC(Remote Procedure Call,远程过程调用)是建立在Socket之上的一种多进程间的通信机制。不同于复杂的Socket通信方式,RPC的初心是设计一套远程通信的通用框架,这个框架能够自动处理通信协议、对象序列化、网络传输等复杂细节,并且希望开发者使用这个框架以后,调用一个远程机器上的接口代码与以本地方法调用的代码“看起来没什么区别”,从而大大减小分布式的开发难度,使得不懂网络编程的程序员也能比较容易的开发分布式系统。
RPC最初是由Sun公司提出,即Sun RPC,后来成为IETF国际标准,至今仍然重要的NFS协议就是最早的基于RPC的一个重要案例。
为了将一个传统的程序改写成RPC程序,我们要在程序里面另外加一些代码,这个过程叫做stub过程,我们可以想象一个传统程序,他的一个进程被转移到一个远程机器中,在客户端及服务端分别有一个stub模块实现了远程过程调用所需的通信功能,比如参数及调用结果的序列化功能,并通过网络完成远程传输,因为Stub与原来的Server使用了同样的接口,因此增加这些Stub代码既不需要更改原来的Client端的调用逻辑,也不需要更改服务端Server的逻辑代码,这个过程如下图所示:
整个RPC流程如下:
- 服务消费方(client)以本地调用方式调用服务。
- client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体。
- client stub找到服务器地址,并将消息发送到服务端。
- server stub收到消息后进行解码。
- server stub根据解码结果调用本地服务。
- 本地服务执行并将结果返回给server stub。
- server stub将返回结果打包成消息并发送至消费方。
- client stub接收到消息并进行解码。
- 服务消费方得到最终结果。
要实现一个完整的RPC框架,就需要如下专有技术。
- 高性能网络编程技术。
- 对象(数据结构)序列化和反序列化技术。
- 自动代码生成或者动态代理编程技术。
比如Java里经典的RPC框架RMI,就用到了Java默认的序列化机制和动态代理编程技术。不过,Java里的RMI及其他语言里特定的RPC框架大都存在一个很明显的缺陷,即仅限本语言的客户端调用,换种语言就无法调用了,而开发需要支持多种语言的RPC框架,其难度至少上升一个数量级。
2、SOAP出现
20世纪90年代后期,XML成为计算机工业新的银弹,几乎所有定义为XML的东西都是好的。1999年底,工业界看到了SOAP的发布。SOAP由微软和DevelopMentor发布,随后交给W3C作为标准。SOAP使用XML作为RPC新的对象序列化机制,IBM则又继续发扬光大这条路线,推出Web Service等整套方案。
SOAP严格意义上是属于XML-RPC(XML Remote Procedure Call)技术的一种变种,一个XML-RPC请求消息就是一个HTTP-POST请求消息,其请求消息主体基于XML格式。客户端发送XML-RPC请求消息到服务端,调用服务端的远程方法并在服务端上运行远程方法。远程方法执行完毕之后返回响应消息给客户端,其响应主体同样基于XML格式。远程方法的参数支持数字、字符串、日期等,也支持数组和其他复杂结构类型,SOAP是第一次真正成功的解决了多语言多平台支持的开放性RPC标准。
一个SOAP请求实例(验证用户信息)如下:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.webservice.tfs.com">
<soapenv:Header/>
<soapenv:Body>
<ser:checkUser>
<!--Optional:-->
<ser:userKey>?</ser:userKey>
</ser:checkUser>
</soapenv:Body>
</soapenv:Envelope>
对应的应答报文如下:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:checkUserResponse xmlns:ns="http://service.webservice.tfs.com">
<ns:return xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</ns:checkUserResponse>
</soapenv:Body>
</soapenv:Envelope>
我们看到,SOAP的报文很复杂而且编码臃肿,由于它是面向机器识别的表达格式,所以程序员很难直接理解他的报文,这个缺陷最终导致了SOAP的末路与HTTP REST的通信方式的兴起。
HTTP REST采用让人容易理解的JSON格式来传递请求与应答参数,因而开发更为方便,但是HTTP REST已经脱离了RPC的范畴了,最明显的特征是:它无需客户端stub代码与服务端stub代码,调用也不再是类似本地方法调用的方式了。
在RPC的路线演化过程中,虽然意外的产生了HTTP REST这个慢慢侵占RPC大部分应用领地的“异类”,并且导致了一度盛行的XML-RPC的灭绝,但同时促进了正统RPC技术走向一个新的发展阶段,追求更高的性能及增加对多语言多平台的支持,成为越来越多的开源RPC框架的目标,典型的代表为Thrift、Apache Avro等新生的开源框架,这些框架在大多数系统、大型分布式系统及移动互联网应用方面被越来越多的公司使用。
3、Zero Ice
提到RPC,不得不说的就是Zero Ice,作为RPC领域的绝对王者,ICE发展至今已经成为一个很强大的微服务架构平台,很适合作为大型分布式系统、电商系统、电信金融等关键系统的基础架构,其优势主要有。
- 在RPC通信这个核心领域里,性能第一、稳定性第一。
- 多语言多平台支持,其服务端可以用包括Java、C++、C#、Objective-C、Python等主流语言协同开发,而客户端支持7中主流语言协同开发(除服务端的5中,还支持JavaScript、PHP)。
- ICE已经成为目前业界最成熟、稳定、拓展性好、功能完备的企业级微服务架构平台,国内外很多大型项目都采用了基于ICE的微服务架构。
更多关于ICE的信息,请参考:https://zeroc.com/
4、从RPC到服务治理框架
与一般的HTTP REST框架不同,一个可用的RPC框架不仅解决了远程调用的问题,也提供了用于服务注册和服务发现的基础设施,比如RMI里的RMI Registry,如下图所示:
使用RMI时,我们所开发的“远程对象(Remote Object)”要注册(Binding)到Registry里,而客户端(Client)则首先需要通过Registry的接口查询到远程对象的访问地址,然后才能发起对远程对象的“远程过程调用”。这种模式表达为更抽象的模型,就是如下图所示的服务注册和服务发现的通用模型。
服务注册和服务发现的模型在后来的Web Service时代被提到一个很高的境界,Web Service的核心架构一般如下图所示。
在Web Service的技术架构中,用XML定义的编程语言中立的接口描述语言WSDL其实来自COBRA中的IDL,基于Socket的复杂RPC调用被简单和容易掌握的HTTP上的SOAP调用所替换。此外,为了防止不同开发商的“互联互不通”及“以自我为中心”的小农思想,IBM倡导了全球服务注册中心UDDI Registry的理念,希望各个厂商都能将自己的Web Service注册到一起,全球互联,服务无国界,但是这次伟大的尝试最终以失败而告终,无数公司不得不重复开发并不是很复杂的软件系统。
后来出现了SOA这个心概念,虽谈业界对SOA这个概念有各种诠释,但是“面向服务的架构”即以服务为中心的分布式架构深入人心,如下图所示是一个理想化的大一统的SOA架构蓝图,我们看到服务注册与服务发布模型及RPC技术依然是SOA的技术核心。
服务注册和服务发布模型成为后来通用分布式系统架构的核心和关键技术基础,也被赋予了一个时髦的新概念–“服务治理框架”,最早的说法可能出自国内BAT的一些架构师。服务治理框架这个概念与SOA在本质上属于同一类,它的一个典型代表是曾经热门的开源项目–Dubbo。下面给出了Dubbo的原理概念图,我们可以看出,相对于SOA架构,Dubbo的服务治理框架中最主要的一个亮点是增加了“服务监控”这个必要的运维特性。
Dubbo同时提出了很多看起来比较吸引人的新特性,比如服务编排、服务降级、访问规则控制,但实际上这并不是核心,作为一个分布式系统的重要基础设施,稳定、高性能的RPC通信及多语言的支持才是关键的核心指标。
5、从单体应用到微服务
我们所说的单体应用指的是服务和应用都运行在同一个Tomcat(其他Web应用服务器)的应用。单体应用的好处如下:
- 通常只建立一个Project即可
- 当系统比较小时,开发、部署、测试等工作都更加简单快捷
- 容易实现项目上线目标
但是当随着系统的快速迭代,就会产生一些难以调和的矛盾与先天缺陷。
- 过高耦合的风险:服务越来越多,不停的变化,由于都在一个进程中,所以一个服务的失败或移除,将导致整个系统无法启动或正常运行的风险越来越大。
- 新语言与新技术的引入阻力:单体应用通常只使用一种语言开发,并且完全使用一种特定的框架,运行在一个进程内,从而导新语言和新技术很难被引进。在互联网应用时代,多语言协作开发是主流,特别是对于复杂的大系统、大平台,而各种新技术层出不穷,拒绝新技术就意味着技术上的落后,从而可能会逐步被市场所淘汰。
- 水平拓展的问题:单体应用从一开始就没有考虑分布式的问题,或者即使考虑了但仍然开发称为单体应用,所以遇到单机性能问题,通常难以水平拓展,往往需要推到重来,代价比较大。
- 难以可持续发展:随着业务范围的快速拓展,单体应用通常难以复用原有的服务,一个新业务上线,通常需要重新开发新服务、新接口。
而微服务架构的出现,恰恰就是为了弥补“单体应用”所带来的各种问题及先天缺陷。在这种新的微服务架构下,整个系统被分解为独立的几个服务,每个微服务可以独立部署在多个机器上,前端可以通过负载均衡器来访问微服务,微服务之间也可以通过同样的接口进行远程通信。
一般而言,如果一个分布式系统具备如下特点,则我们可以称之为“微服务架构”;
- 任何一个服务都由多个独立的进程提供服务,这些进程可以分布在多台物理机上,任何进程宕机,都不会影响系统提供服务。
- 整个系统是由多个微服务有机组成的一个分布式系统,微服务架构从某种意义上来说可以看做服务治理框架的进一步延伸。
微服务架构背后的思想和顶层设计无疑是一个巨大的进步。 我们说了这么多年面向服务设计与建模的梦想,终于在分布式时代里被第一次真正重视和彻底实现,而这一切都源自全新的微服务架构。
总结下来,当前主流的微服务架构可以分为以下几类。
- 基于传统的高性能RPC技术和服务治理能力的微服务架构,这个领域的王者为ZeroC IceGrid。
- 以HTTP REST为通信机制的通用性微服务架构,最典型的为Spring Cloud。
- 基于容器的技术,目标是部署在公有云平台上的微服务架构基础平台,这种微服务架构平台没有提供特定的RPC通信机制,只保证TCP通信的可达性,所以理论上任何分布式应用都可以运行在微服务架构平台上,言外之意就是要选择合适的通信协议,比如REST、Thrift或者自定义的某种TCP通信协议。这个领域的王者为Google的Kubernetes。
参考:架构揭秘从分布式到微服务