微服务治理:体系、架构及实践
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.2 服务治理发展历史

1.2.1 单体架构及治理

1.2.1.1 单体架构的进化

一个系统的发展壮大总是由其业务驱动的,系统的访问量、数据量、业务的复杂度直接决定了系统的应用架构。一个小网站系统或一个普通的企业Web应用在访问量和数据量较小时,往往所有的功能模块都打包在一个工程中,并最终发布为一个部署包(Java中是war应用包),并部署在一个Web容器中运行,如图1.2所示。

图1.2 单体架构

随着业务的发展,系统越来越复杂,有的开发人员习惯在JSP页面上实现所有的功能,有的开发人员则注重把一些通用功能抽取为JavaBean,不同开发人员的不同开发风格会给系统的维护带来严重的影响。这时候,我们开始思考对功能模块进行分层设计,以便对功能模块的设计提供统一、易于维护的标准模式,这样也能让系统内部单个模块的设计有效地解耦。在分层设计中,应用最普遍的是MVC设计模式,最典型的MVC是JSP+Servlet+JavaBean的模式,但这种组合的约束性太弱,不易形成统一的规范。对于模式的应用,最好的途径莫过于直接使用一些基于模式设计的、具有一定约束性的框架(Framework),利用别人搭建的舞台(Framework)来进行表演(开发应用)。这个时期很多公司都在开发并分享自己的框架,大浪淘沙,最终慢慢沉淀下来一些设计合理、普及性广泛的框架,比如Java中的Struts1/2、Spring MVC,Go中的Django、Ruby中的Rails等。

基于这一类的MVC框架,将模块内偏向展示的部分抽取成独立的视图层(View),将负责请求处理流转控制的业务代码独立为控制层(Control,也叫活动层),为了防止控制层太重,还可从其中将负责具体业务逻辑的代码抽取为一个独立的服务层(Service),以集中操作文件、数据库等资源。各层之间弱耦合,只有一个统一的业务模型(Model)贯穿前后。这样,一个功能模块的开发就可以分别由团队内的不同人员(UI设计师、前端工程师、服务端工程师)负责,这是系统微观方面的拆分,如图1.3所示。

图1.3 分层架构—MVC分层

使用MVC框架,一定要遵守该框架的规则,它有一定的强制性。MVC框架使应用程序输入、处理和输出分开。使用MVC的应用程序被分成三个核心部件:模型、视图和控制器(可以从其中再隔离出服务),它们各自处理自己的任务。

单体应用的开发和调试都很简单,部署也相对容易,只要控制好Session在不同节点的共享问题(可以采用前端Cookies缓存数据,也可采用后端的数据库或统一缓存中心来缓存数据),只需要把打包应用复制到服务器端,再结合负载均衡器就可以轻松实现应用的扩展。在早期,这类应用运行得很好。由于系统架构及部署架构都比较简单,治理方面的需求并不强。

这个时期的复杂度,主要来自于系统功能不断扩充后,系统膨胀导致的开发复杂度上升,这个复杂度既体现在单个功能模块的前、后端的耦合度上,也体现在模块间的依赖和模块的复用性上。

1.2.1.2 组件库及其治理

架构分层,尤其是类似MVC等框架的导入,解决了单个功能模块的复杂度问题。在模块的复用性上,将一些基础的或者通用的功能模块独立抽取出来,形成独立的组件库,组件库的各个组件可独立维护,并按需组装到不同的应用中,基于组件库的开发模式如图1.4所示。

图1.4 基于组件库的开发模式

组件库的出现有效改善了单体系统开发的复杂度,诸如基础运行框架、认证、授权、资源(文件、DB、缓存等)等对外无依赖且自洽的平台和组件可以被抽取出来,独立地按工程开发并发布为独立的基础组件。而更上层一些靠近业务的通用模块(可能会依赖其他组件)也可以抽取为独立工程并发布为通用组件。有了组件库之后,应用的相当一部分能力集成现有组件即可,其工程的体量直接降了下来,业务开发人员就不需要再关注“一大坨的”底层功能代码。

有了组件库之后,开发的复杂度从应用转移到了组件库,尤其是在组件的数量攀升之后。组件的复杂度来自多个方面:①每个应用会依赖多个特定版本的组件;②每个组件,尤其是通用组件,可能会依赖其他组件;③每个组件会分多个版本。最终,应用和组件之间的依赖关系会形成如图1.5所示的状况。

图1.5 应用和组件之间的依赖关系

可以看到,应用和组件之间的依赖及组件之间的依赖形成了一个网状的关系,而组件的版本又增强了这个依赖的复杂度。大量的应用、组件、组件版本最终形成了一个复杂的直接及间接的依赖关系。有了复杂度就有了治理的需求,这个时期的治理需求主要是对组件库的治理。

笔者之前曾在一家大型ERP企业负责组件库的构建及治理工作,要定期给出组件治理报告,分析组件的状态及依赖,包括哪些组件是核心组件(依赖最多);组件依赖是否合理、是否有循环依赖;哪些组件版本可以归档、不能再被使用;组件版本升级涉及多少线上应用、关联组件是否也要同步升级;等等。通过组件库的治理,可以有效控制功能的版本,防止版本失控,从而降低应用的维护难度及成本。

1.2.1.3 单体应用的不足

通过架构分层及组件库,虽然有效降低了应用系统的复杂度及维护成本。但随着业务不断发展,一个简单的应用总会随着时间的推移逐渐变大。在每个迭代周期中,开发团队都会面对新“故事”,然后开发许多新代码。长此以往,一个小而简单的应用会变成一个巨大的“怪物”。笔者曾在入职一家新企业的时候,接手了一套老平台系统的维护工作,这套百万行代码的系统经历了无数程序员之手,功能巨多,代码纵横交错。看了两个星期代码之后,笔者直接崩溃了,不得不基于JDT写了一个代码梳理工具,很多单体系统最终都会发展成这样一个“怪物”。

一旦应用变得庞大又复杂,对任何接手的开发团队都是个“噩梦”。这时,没有一个开发者能够通盘了解它,团队对系统的控制能力降低,我们不知道修改Bug和添加新功能是否会引入不可测的风险,修改一行代码都会瞻前顾后、顾虑重重。这种背景下,程序员很难有什么成就感可言,团队的稳定性也就可想而知了。

单体应用也会降低开发速度,虽然可以拆成组件,但最终依然还是要合并部署。应用越大,启动时间越长。笔者曾经见识过一个银行的内部系统,启动时间居然超过了20分钟,其间涉及大量组件的初始化工作。如果开发者需要经常重启应用进行调试部署,那么大部分时间就要在等待中度过,生产效率会受到极大影响。

单体应用在不同模块发生资源冲突时,扩展将会非常困难。比如,一个模块主要进行业务逻辑计算,应该部署在计算型主机上;而一个缓存模块则更适合部署在内存型主机上。如果这些模块都部署在一起,可用硬件的选择面将会非常窄,成本也会直线升高。

最后,单体应用一旦长大了,容易“尾大不掉”,很难进行架构升级和技术优化。无论是时间成本、人力成本,还是替换成本,都很高昂。这是一个无法逾越的鸿沟,这个时候,任何治理手段都会失效,往往最终会为最初的选择付出昂贵的代价。

总结单体应用的发展历程:最初的“小而美”的核心业务应用,会随着业务的发展慢慢成为一个难以理解的“大而全”的“怪物”。单体的复杂度导致系统可靠性降低,任何人在此系统上进行扩展都会投鼠忌器,更谈不上升级技术和提高开发效率了。最终的结果是无人愿意接手此应用,敏捷开发和部署也无从谈起。

正是由于单体应用的种种弊端,所以在业务发展的过程中,往往会对应用按更细化的业务进行拆分,拆成独立部署的不同的小应用,如图1.6所示。这时候,原来的内部调用关系就变成了跨网络的远程调用,系统间的集成需求也就浮上了水面,企业级应用和互联网应用由于需求的侧重点不同,走出了两条既有交集、又有很大差异的路。

图1.6 单体应用按业务拆分成多个小应用

接下来,我们介绍企业级应用的拆分及整合之路。

1.2.2 企业SOA——EAI/ESB及治理

随着企业IT建设的不断深入,IT系统越来越多,由于建设人员、建设时期不同,差异很大,技术不断发展,每个时期采用的技术也不一样,这些系统往往会形成独立的竖井。随着业务的不断发展变化,系统之间交互的需求越来越多,把这些“竖井式”的系统进行一体化整合也随之被提上日程。

1.2.2.1 点对点式(P2P)的直连模式

这是最原始的整合模式,直连手段也五花八门:文件交换、RMI技术、基于HTTP的远程调用……不一而足,如图1.7所示。这种EAI方案虽然取得了一定的成功,但存在种种致命缺点。一方面,这种模式最终会导致内部应用系统之间形成一张网,造成系统之间的强耦合,随着集成的应用越来越多,程序员需要编写和维护的远程直连相关代码的工作量也迅速增长,不易于系统及整个IT环境的升级维护及管控;另一方面,这种解决方案的出发点还是基于各个业务系统的需求,而不是从企业IT发展的整体需求出发,使用的技术和协议都很随意,格局所限,导致只能各自为政,没有在整体的基础之上适应未来的变化和发展。因此,P2P的集成方式很快就被摒弃了,尤其是在系统数量很多的大型企业或网站之中。

图1.7 点对点直连的整合模式

1.2.2.2 星型连接模型

为了克服点对点集成的缺点,逐渐出现了基于中间件的企业应用集成方案。如图1.8所示,通过建立一个由中间件组成的企业应用底层架构,来联系整个企业的异构应用。这些作为集成引擎的底层中间件主要包括RMI、CORBA、DCOM、J2EE/JCA、EJB等。

图1.8 基于中间件的星型集成方式

使用这些分布式处理中间件技术解决P2P的问题时,也存在一定的局限性。这些技术虽然都基于某种标准,但其传输、数据定义、访问模型等机制均不一样。同时,由于厂商利益导致的技术对抗,这些中间件之间很难互联互通,比如基于Java的RMI协议和基于微软的DCOM之间就无法直连。如果企业内部采用多种这样的模式,容易形成几个大的竖井,这也在客观上阻碍了这种模式的进一步推广。

1.2.2.3 SOA/ESB连接模型

基于中间件的星型集成方式走不通,通用性更广的面向服务的架构(SOA)随之被提了出来。SOA是一种组件概念模型,它建议将应用程序的不同功能单元(称为服务)进行拆分,并通过定义良好的接口和契约将这些服务联系起来,接口是采用中立的方式进行定义的,它独立于实现服务的硬件平台、操作系统和编程语言,并有效兼容各种协议。这使得构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。

SOA概念的具体落地形式(也是核心)就是服务总线(ESB),那么什么是服务总线呢?简而言之,我们可以把ESB想象成一个连接所有企业级服务的脚手架,是一种松耦合的服务和应用之间标准的集成方式。

服务总线本质上就是传统中间件技术与XML、Web服务等技术结合的产物,这些中间件包括MQ、各种网络或数据的协议转换及适配器、流程引擎等。服务总线为应用系统之间的互联互通提供了一个基于网络的、中心化的连接中枢,它可以通过一整套标准化的协议适配器(比如JMX协议、SOAP协议等)来支持应用之间在消息、事件、服务级别上动态地互联互通,被接入的应用还可以通过流程化的编排,把这些接入的基础服务聚合成更大粒度的复杂服务(服务编排),并通过诸如UDDI这类协议暴露出去,供第三方系统查阅和调用。

如图1.9所示,ESB中的核心部件是Web服务,它由如下几大组件构成。

图1.9 SOA/ESB集成架构

● WSDL(Web服务描述语言):是一种规范,定义如何用XML语法描述Web服务。WSDL定义了一套基于XML的语法,将Web服务描述为能够进行消息交换的服务访问点的集合,实现了以结构化的方式对Web服务的调用或通信交易进行描述。

● SOAP(简单对象访问协议):是一种基于HTTP协议和XML规范的、轻量的、简单的Web服务的标准通信协议。

● UDDI(通用描述、发现与集成服务):是一种目录服务,企业可以使用它对Web Service进行注册和搜索。

● BPEL4WS(基于Web服务的业务过程执行语言):实现对Web服务的流程化编排。

除了Web服务,各大软件厂商还共同制定了中立的SOA标准来保证其落地。这一努力最重要的成果体现在3个重量级规范上:SCA、SDO和WS-Policy。SCA和SDO构成了SOA编程模型的基础,分别定义了服务组件的开发规范和数据的封装规范,而WS-Policy建立了SOA组件之间安全交互的规范。

此外,服务适配器也是重要组件,它比较彻底地解决了不同协议互相转换的问题,可以把不同数据格式或模型转成标准格式,比如把XML的输入转成CSV传给只能处理CSV数据的遗留服务,把SOAP 1.1服务转成SOAP 1.2等。它还有一个重要功能是消息队列和事件驱动的消息传递,比如把JMS服务转化成SOAP协议。

由于既支持CORBA这类强同步的调用,也支持基于诸如JMS这类MQ协议的异步调用机制,所以在ESB上可以实现如下的应用架构:

● 服务驱动的架构(SOA)—分布式应用由可重用的服务组成;

● 消息驱动的架构(Message Driven Architecture,MDA)—应用之间通过ESB发送和接收消息;

● 事件驱动的架构(Event Driven Architecture,EDA)—应用之间异步地产生和接收消息。

图1.10是一个ESB的典型案例的架构图。

图1.10 ESB的典型案例的架构图

1.2.2.4 SOA治理

我们首先引用一个流传甚广的真实故事来看看为什么SOA需要治理。

在20世纪90年代后期,Sun推出了一系列产品,包括Java、Solaris等,他们鼓励用户使用这些产品,但当时网速太慢了,在线下载几百兆的软件几乎无法实现。因此,Sun在网站上推出了一个电子商务服务A,通过信用卡支付10~20美元快递费用,就可以免费获赠Sun的产品光盘。负责这个电子商务服务A的程序员,另外写了一个在线服务Z,用来完成信用卡付账交易,它运行在内网中,采用HTTP传输加密的XML消息。服务A上线之后,一直工作得很好。不久之后,这个程序员被调到Java开发组,但是Sun的Java网站提供一个类似MSDN的Java产品光盘订阅服务,称为服务B,这个程序员每季度向订阅者寄送最新的Java产品光盘。订阅者也要通过信用卡支付订阅费。碰巧这项工作又交给了这位程序员来完成。他不愿意重写信用卡结账服务Z,既然原来的那个服务通过HTTP暴露在内网里,何不直接用?他简单地复用了这个信用卡结账服务Z,完成了任务。这样,在20世纪90年代后半期,这位程序员率先实现了企业服务的复用。

这样就形成了一个有趣的局面,即服务A中包含一个子服务Z,而服务B又依赖于服务Z,服务Z实际上成为了一个公共服务。但这个秘密只有那个程序员和少数几个人知道,Sun的经理们对此懵然不知。几年之后,这位程序员离开了Sun,随着他的离去,这个秘密变得更加不为人知了。

随着互联网的发展,人们已经习惯从网上直接下载软件,服务A变得越来越过时。终于有一天,Sun的一个经理决定关闭服务A。结果意想不到的事情发生了,随着服务A的关闭,服务Z也被关闭了,这就导致了服务B全面崩溃,所有的订阅者都无法付款了。

这就是一个在缺乏治理和监管的情况下发生的典型事故。在SOA这个大背景下,涉及的应用及其他软硬件资源越来越多,这时候,我们迫切需要知道:IT整合的整体规划是否合理;线上目前共注册了哪些服务;哪些服务是可用的;哪些服务是核心服务;某些敏感服务是不是做了权限控制;服务的依赖关系是什么;一个服务发生变更,是否通知了依赖它的相关周边服务;等等。这些都是对服务的治理需求。实际上,“服务治理”这个概念就是伴随着SOA的发展被同步提出的。

毋庸置疑,SOA整个体系架构涉及的规范多、技术栈长、流程复杂,从战略规划到架构落地的过程中,如果缺少一定的治理保障,导致过程中出现缺失,就算我们最初有个100分的战略规划,最终也有可能收获一个不合格的实现结果,图1.11形象地描述了这个过程。

图1.11 缺少治理保障的SOA落地效果

所以,实施服务治理的目标就是防止SOA实施的失控。一般来说,企业都会成立专门的团队或委员会来负责SOA治理,负责创建策略来执行治理和角色标识、授权并保证获得了决策与策略执行能力的人员的可靠性。这里的治理与管理是有区别的,二者之间通常存在以下差异:治理决定谁具有决策的权力和责任,为决策提供框架,保证做“对”的事情,走“正确”的路;管理是进行决策和实施决策的过程。

因此,治理讨论应该如何进行决策,而管理是进行决策和执行决策的过程。简单来说,治理委员会需要处理三个主要问题:

● 为了确保有效的IT资产管理,需要进行哪些决策?

● 谁应该负责进行这些决策?

● 此类决策如何执行和监视?

作为治理实现的核心部分,需要建立服务水平协议(Service Level Agreement,SLA,又称服务可用性协议)的衡量指标体系及监控评估体系,以持续地对其进行改进。同时,也会收集相关服务的性能度量来表征治理的有效性。

大多数企业都会采用某种业界通用的方法论来逐步实施SOA,该方法首先通过收集业务需求并对其进行抽象和优化来进行基础服务的建模;有了基础服务之后,就可以组装新的及现有的服务来实现业务流程;创建的这些服务及流程资产将被部署到安全的环境中被使用;在使用的过程中,还要持续地对这些资产进行优化管理。“建模—组装—部署—管理”这个过程周而复始,这就是著名的4阶段的SOA生命周期方法论。

与此对应,SOA治理同样遵循生命周期原则,IBM推出的“SOA治理及管理方法”(SGMM)就把服务治理的生命周期定义为如下4个阶段:

● 计划:确定SOA治理的重点;

● 定义:定义SOA治理模型;

● 启用:实现SOA治理模型;

● 度量:改进SOA治理模型。

SOA治理生命周期产生一个治理模型来管理SOA生命周期。这两个生命周期相互配合、同时运行,一起被使用,产生SOA组合应用程序及其服务。图1.12描述了它们之间的关系。

具体来说,通过对UDDI服务注册中心的梳理,可以获取服务提供者、服务使用者的相关信息,继而推导出服务或系统之间的依赖关系;通过ESB内置的日志监控,可以获取服务调用过程中的性能指标等信息;通过ITIL等运营系统,可以获取服务的相关维护信息,再结合UDDI服务注册中心不同时期的服务注册信息和依赖关系,可以获取服务变动情况跟踪报告和依赖变动跟踪报告,如图1.13所示。这些指标信息,构成了SOA服务治理的相关指标报告,并提交给治理委员会成员进行相关的分析,据此提出优化建议,从而驱动SOA架构的持续调整和深度优化。

图1.12 SOA治理生命周期和SOA生命周期的协同配合

图1.13 SOA治理的度量指标

1.2.2.5 SOA的问题

主导这一时期SOA标准及治理标准的都是一帮老牌大厂,像IBM、Oracle等。正因如此,企业级SOA最大的问题就是它所涉及的技术栈太重,相关规范太复杂,导致落地很困难。毕竟,对于软件厂商而言,技术太简单、落地太容易的话,就很难在咨询及服务上卖出大价钱。

同样,这个时期的服务治理还是一种比较粗粒度的行为,更多的是通过诸如ITIL这类企业内部的IT流程管理来实现服务的注册和梳理。在治理过程中,人工行为占了很大的比重,自动化及智能化水平不足。比如,这个时期的WebService UDDI服务注册采用人工方式将服务的接口信息(服务名、服务URI等)配置到服务注册中心。它的问题是需要人工收集服务接口信息,这个过程可能产生滞后或者错误的信息,运维代价大、“人肉”方式无法对服务进行细粒度的管控。另外,缺少服务运行时动态治理能力,面对突发的流量高峰和业务冲击,传统的服务治理在响应速度、故障快速恢复等方面存在不足,无法敏捷地应对业务需求。在大的软件厂商的有意推动下,治理流程及架构和平台复杂、治理组织机构臃肿、对人员要求高等因素也增加了服务治理的实施难度,SOA生命周期及治理周期的复杂度双重叠加,导致落地难度直线上升。

另外,像ESB这类组件,本身就成了一个最大的“单点”,虽然可以采用“主备”模式提高可用性,但在容量扩展上依然存在瓶颈,当服务数量及调用量不断增长时,ESB往往成为最先倒下的那张多米诺骨牌。

1.2.3 分布式服务及治理

1.2.3.1 互联网服务化

在互联网领域,大型网站基本都是从一个小站点逐步演变而来的。这点和企业级应用很不一样,企业内部的系统建设一般都是先由特定的一批人的需求零星独立建设的,系统多了,有了互联互通的需求之后,才开始做整合。当网站的业务规模很小的时候,采用的也是类似如图1.1所示的单体架构,随着业务的快速发展,站点的所有功能都堆积在一个系统中的问题就开始显现,包括功能模块及代码互相耦合、资源冲突、维护麻烦、编译时间变长等,这些单体应用会遇到的问题,网站也都会遇到。除此之外,膨胀的单体架构对网站还有另外几个致命的影响。

● 对SAP-ERP、Oracle-DB这类典型的企业级软件而言,产品版本以年为单位发布;而对一个快速发展的站点而言,为了适应业务的发展,往往需要不断试错,会频繁上线新功能,并根据用户的使用体验进行迭代更新。这会导致频繁发版,频率甚至会达到每天几十次。如果采用单体架构,仅编译就需要十几到几十分钟,测试和发布部署都极其麻烦,完全无法适应业务的快速发展。

● 一个站点各个功能的访问总是不均衡的,比如对购物网站来说,商品列表页和详情页的访问频度总会很高,一个秒杀的功能甚至会导致瞬时几十倍的流量暴增,而评论、客服这类功能的使用频率相对较低。如果这些功能都堆积在一个单体架构中,高频应用将占据绝大部分系统资源,就会导致其他功能的资源受挤占,从而影响用户体验。

基于如上种种问题,一个网站发展到一定规模之后,往往会将业务按产品线进行拆分。比如,美团就将旗下业务拆分为美食、酒店、电影、购物这几大产品线,归不同的业务团队负责。

业务映射到技术上,技术架构及部署策略同样需要跟随产品线进行同步拆分,将一个网站拆分成许多不同的应用,并独立部署和维护。研发团队也相应地拆分成不同的产品线团队,各自负责不同业务系统的研发及维护。

网站系统和企业系统的一点不同在于,它在数据资源的唯一性上做得比较彻底。比如,在企业系统中,集团公司的办公系统可以只有集团公司的用户,分公司的办公系统可以只有分公司的用户,这两套系统之间的公文传输可以通过ESB来完成。在系统建立初期,实际上并不强制一定要有一套统一的用户中心(例如LDAP)。而对于网站来说,初始的用户体系就必须只有一套,一个用户ID能在各条产品线中通用,一个用户在网站的所有系统中只有唯一的一套标识(俗称oneID),否则,用户根本无法在网站中进行随意跳转。所以,大型网站的用户信息这类基础数据往往都存储在同一个数据库(集群)中。如果每个应用都直接连接用户数据所在的数据库,就算每个应用节点只分配几个连接,在集群规模下,总的连接数也将达到几万甚至几十万个,这完全超出了数据库的连接数上限,会导致数据库连接资源不足,从而拒绝服务。

这时候就要考虑服务化的架构了,既然每一个应用系统都需要执行许多相同的业务操作,比如用户管理、商品管理、仓储管理等,那么完全可以将这些通用的业务提取出来,独立部署。由这些可以复用的业务连接数据存储层,提供共用的业务服务,这样应用系统就可以做得比较薄,而把逻辑集中到后台服务中,由共用业务服务完成具体业务操作。具体架构如图1.14所示。

图1.14 互联网分布式服务化架构

服务化的架构分层带来了很多的好处。

服务化在很大程度上解决了复杂性扩散的问题。比如,随着并发量越来越高,用户管理的访问数据库成了瓶颈,需要加入缓存来降低数据库的读压力,于是架构中引入了缓存,如果没有统一的用户管理服务层,各个业务线都需要关注缓存的引入导致的复杂性,而由于统一的用户管理服务层的存在,可以将缓存操作集中在这里进行,各个前端应用则对此无感;另外,随着数据量越来越大,数据库需要进行水平拆分,于是架构中又引入了分库分表,如果有了统一的服务层,分库分表策略集中在服务层进行即可,各个业务线都不需要关注分库分表的引入导致的复杂性。

天下武功唯快不破,“快”就意味着机会,尤其是在这个竞争充分、变化快速的社会中,服务化带给业务最大的好处就是,可以让业务系统迅速适应业务高速发展的需求。通用业务及基础技术能力下沉,这些能力从业务系统中剥离出来之后,由专门的部门或者组织维护,业务应用就可以变得更轻、更专注,开发者更多的时候就可以通过很少的代码把这些服务聚合起来,封装成业务功能暴露给用户。业务系统更小、更轻,意味着可以更频繁地上线,更快速地修改,更快、更简单地聚合出新的功能推给市场,只有这样才能支持业务不断试错。服务化做得好的架构,必然是服务层越来越厚,业务层相对较薄,如图1.15所示的就是一个典型电商平台的分布式服务化架构。

图1.15 电商平台的分布式服务化架构

1.2.3.2 分布式服务框架

随着服务化的不断深入,被下沉的服务数量越来越多,另一方面,随着流量的增大,单个服务的集群规模不断扩大,这就迫切需要一个统一的分布式服务框架来对服务进行集中的管理。参考企业级SOA架构,互联网领域提出了“轻量化SOA架构”,仍然引入服务注册机制和远程调用机制,负责服务的注册、发现、路由、调用等典型的SOA能力,但是摒弃了复杂的服务编排和低效的协议适配(同构系统中,兼容多种协议的需求意愿并不强)。

互联网领域的分布式服务化虽然复用了SOA架构(做了简化),但依然有很大的不同。首先,由于互联网服务具有普遍集群化的特点,需要在分布式服务框架中引入服务负载均衡的机制;针对互联网服务流量大、并发高、可靠性要求高的特点,在分布式服务框架中还引入了限流、降级、熔断等保护机制。这些对服务的管控和运维能力被下沉到框架层面之后,可以让业务开发人员专注于业务逻辑实现,避免冗余和重复劳动,规范研发、提升效率。

分布式服务化比起企业SOA的另外一大不同就是规模。规模上去了,一些原来靠人工完成的功能就不再适用了,比如SOA中的UDDI服务注册,采用的是手工注册的方式,而在分布式服务框架中,服务注册中心则采用了服务运行时自动注册和自动发现的机制。而且,随着云计算技术的快速发展,大型互联网企业往往建设自己的云服务平台,中、小型网站也可以购买第三方的云服务。结合云服务的资源编排及调度能力(IaaS,资源即服务),应用服务的上线、调配可以采用自动化、批量化操作。因此,分布式服务的自动化程度要比企业SOA高。如图1.16所示为互联网分布式服务框架的典型架构。

1.2.3.3 分布式服务治理

同SOA类似,分布式服务同样面临治理的需求,同时由于服务集群规模大,梳理服务之间的结构及依赖要比之前更困难,很难靠人工完成,因此分布式服务治理的自动化程度要远高于SOA治理。这个时期的服务治理不仅包含服务的度量,还会根据一些预定义策略,自动执行服务管控的操作。比如,一旦监控到某个服务的调用失败率超过SLA中预先定义好的阈值,服务自动触发熔断保护机制。“自动化”是服务治理在这个时期的一大特点。

图1.16 互联网分布式服务框架的典型架构

分布式服务治理包含服务度量和服务管控两大部分。服务度量具体如下:

● 服务基础信息:包括服务唯一标识、访问协议、版本和归组等信息。

● 服务管理信息:从ITIL这类运维管理系统中获得的对服务管控的相关运维管理信息。

● 服务质量(健康度):根据被调用服务的出错率、响应时间等数据对服务健康度进行的评估。

● 服务依赖:根据服务直接的调用及被调用关系,推导出服务与其上下游服务的依赖关系。同时根据监控获取的调用数据,评定依赖的强弱关系。

● 服务分布:提供服务在物理空间上的拓扑分布情况,包括服务在不同计算中心、不同机房,甚至不同机架上的分布情况。

● 服务容量:根据所提供服务的总能力及当前所使用容量进行的评估,其中能力是指对于请求数量方面的支撑情况。

● 服务调用:服务在线上被调用的次数及基于此的一些统计分析,包括TopN的一些统计排行等。

通过服务度量,就能够对线上服务的运行状况有一个清晰的了解,并据此做出相应的服务管控动作。当然,也可以结合基于行业领域知识和运维场景领域知识的运维专家系统,做自动化的管控。接下来,再从服务管控的角度看看都能对服务做哪些操作。

● 服务上、下线:服务的批量上线部署及批量下线。

● 服务路由:对服务路由策略的管理。

● 服务限流:针对高流量导致的服务负载过高的一种保护机制。

● 服务降级:在异常情况下,保证服务基本可用的一种保护机制。

● 服务熔断:是服务降级的一种特殊体现,主要防止在异常状态下,服务出现“雪崩”状况。

● 服务授权:针对服务调用者对某些敏感服务的访问授权管理。

以上治理的相关详细内容,将在后续章节中详细讲解。图1.17描述了互联网分布式服务及其治理之间的整体关系。

图1.17 互联网分布式服务及其治理之间的整体关系

1.2.4 微服务及治理

1.2.4.1 大平台、微服务

在容器技术出来之前,服务部署模式以物理机和虚拟机系统为主,虽然服务可以被拆分得很小,但考虑到操作系统的部署成本,最终这些服务还是会被合并部署。当然,也可以采用在同一个操作系统内,启动多个应用服务进程来做服务隔离,但依然无法在CPU、内存等资源利用方面做到很好的隔离,而且服务的合并部署必然导致服务逻辑之间存在耦合。

以Docker为代表的容器技术出来之后,对软件应用的开发、运维产生了深刻的影响。由于容器比虚拟机轻量,消耗的系统资源极少,启停速度比虚拟机提高了一个量级,在资源利用率上,容器的部署密度也比虚拟机高。另外,诸如Dockerfile这种容器定义文件,不但能够定义使用者在容器中需要进行的操作,还能够定义容器中运行软件需要的配置,于是,软件开发和运维终于能够在一个配置文件上达成统一。这些都极大地降低了服务部署及运维的成本。原来服务聚合部署的模式可以被拆分成一个服务一个容器的单服务部署模式,服务的粒度也越来越细,这就是所谓的微服务模式。

在此背景下,大型互联网公司的分布式服务应用出现了一种两极分化的趋势。一方面,随着业务规模和访问量的增大,服务集群(平台)的规模越来越庞大,提供的服务及服务的分层也越来越复杂;另一方面,底层单个原子服务的粒度却越来越小,越来越扁平化。这种趋势用一句话简单概括就是:大平台、微服务。图1.18就是从网络上收集的一些互联网公司内部服务的调用关系图。

大平台、微服务是一种必然的趋势。服务粒度被拆得越细、功能越单一,其可组装性就越好。粒度更小的服务可以更加灵活地组装出复杂程度不同的顶层服务。打个比方,原子服务就像蜂巢中规则的六边形小蜂房,通过这些微小蜂房的有序组织,可以构建出巨大的、适应不同环境的蜂巢,如图1.19所示。

图1.18 微服务集群案例图

图1.19 蜂巢内外部结构

1.2.4.2 微服务的智能化、立体化治理

在大平台、微服务模式下,服务的数量非常庞大,服务的分层日趋复杂,一个业务请求贯穿的服务数量越来越多,此时服务治理的广度、深度、难度都将达到前所未有的程度。量变到一定程度就会导致质变,我们每天在线上都可能会遇到新的问题,靠预先定义的专家系统的自动化运维已经很难适应此时治理的需求,需要通过一些算法来根据大量的线上运维数据(日志、监控信息、服务信息等)进行自动学习,以辅助我们对线上问题进行自动归类和判别。更进一步,结合机器学习的成果,甚至可以让集群自身以发生过的人工干预历史作为学习样本,自动生成规则策略,进一步降低人工干预的程度,从故障发现到诊断再到自愈,整个流程由智能大脑统一控制,并由自动化和智能化自主实施,成为一个自耦的系统,真正朝着智能化治理方向发展。

同时,微服务架构模式所要求的领域隔离性也会对传统的IT资源编排和调度、组织管理模式、研发策略、测试方法都带来影响。服务治理的范围也从线上的应用服务扩展到更大范围的研发、测试、运维、协同管理等领域,从而实现立体式的治理覆盖。

我们将在1.3节中对微服务治理的对象及范畴展开更进一步的讨论。