单体应用程序与面向服务的应用程序
传统的大型单体应用程序在一个组件中包含了所有逻辑和功能,各个代码片段之间相互交叉并依赖。它是一个编译后的源代码片段,创建了一个包含应用程序大部分或者所有功能的可执行文件。图3-1表示了一个典型的单体应用程序。
这也是大多数发展成单体应用程序的系统看上去的样子。在图3-1中,你可以看到5个独立的开发团队在相互重叠的部分同时工作。我们无法知道在某一个时间点,究竟是谁在哪一块上工作,也不难想象代码变更所导致的冲突和问题。代码质量,以及因此产生的系统质量和可用性也会受到影响。此外,系统变得越来越复杂,单个开发团队想要更改代码也变得越来越困难,不得不面对与其他团队的协作、互相冲突的改动,以及组织内部纠缠不清等问题。
图3-1:一个大型的、复杂的单体应用程序
图3-2展示了由一系列服务所组成的同样的应用程序。每个服务都有一个清晰的负责人,并且每个团队都有一个清晰的、无重合的职责范围。
图3-2:一个大型的、复杂的但基于服务的应用程序
面向服务的架构能够将一个应用程序拆分成多个不同的领域,每个领域由单独的团队来负责管理。这种职责隔离对于构建大规模应用程序至关重要,可使各个服务之间独立地完成工作,避免影响到系统中其他组中开发人员的工作。
当构建高可伸缩的应用程序时,基于服务的应用程序提供了以下几点好处。
伸缩性决定
这使你能够从更细粒度来考虑伸缩性方面的决定,从而进行更有效的系统和组织优化。
团队分配和关注
面向服务的架构使你能够将任务分配给不同的团队,让它们关注于系统中不同的可伸缩和高可用需求,并让它们有信心知道,自己的决定会对整个系统产生合理的影响。
复杂的本地化
使用基于服务的架构,你可以将各个服务看作一个个黑盒,只有服务的所有者需要了解该服务内部的复杂逻辑,其他开发人员只需要知道服务所能提供的能力,而不需要知道它内部的工作原理。这种认知和复杂性上的隔离,能帮助你创建更大型的应用程序,并且能更有效地管理它们。
测试
基于服务的架构比单体应用程序更容易测试,从而可以增加系统的可靠性。
但是,如果服务之间的边界没有设计好,面向服务的架构会增加系统整体的复杂性。这种复杂性会导致更低的可伸缩性,并降低系统的可用性。因此,选择合适的服务和服务边界至关重要。
所有权收益
让我们来看一对服务。
在图3-3中,我们可以看到由两个独立团队所管理的两个服务。“左服务”正在使用由“右服务”提供的能力。
图3-3:一对服务
我们先从左服务所有者的角度来看这张图。显然,左服务的团队需要了解左服务的整体结构、复杂性、正确性、交互操作、代码以及其他内容。但是它们需要了解右服务的什么呢?首先,左服务团队需要了解右服务的以下几件事情:
该服务提供的能力。
如何调用那些能力(API语法)。
调用那些能力的意义和结果(API语义)。
这些是左服务需要了解的基本信息。那它们不需要了解右服务的哪些信息呢?这包含很多内容,例如:
左服务不需要了解右服务是一个单独的服务,还是多个子服务的组合。
左服务不需要了解右服务需要依赖其他什么服务。
左服务不需要了解右服务是用什么语言编写的。
左服务不需要了解右服务所使用的硬件或系统架构。
左服务甚至不需要了解谁来提供右服务(但是,它们需要知道遇到问题时联系谁)。
如图3-4所示,右服务可以很复杂,也可以很简单。但是对于左服务的团队成员来说,右服务就像一个黑盒,不知道其内部的结构是什么样的,如图3-5所示。只要左服务知道这个黑盒的接口是什么(API),就可以使用这个黑盒所提供的能力。
图3-4:右服务的内部情况
图3-5:右服务的复杂性被隐藏起来
出于管理的目的,左服务必须能够依赖右服务所提供的约定。这个约定描述了左服务如何使用右服务的所有事项。
约定包含以下两部分。
服务的能力(API)
服务的用途。
如何调用服务以及每个调用的意义。
服务的响应性
API使用的频率
什么时候可以使用API
API响应的速度
API是否存在依赖
所有这些信息组成了右服务提供给左服务的约定。只要右服务遵守这个约定,左服务就不需要知道或者关心右服务是如何来实现这些约定的。
该约定的响应性部分被称为服务等级协议,或者SLA。它是让左服务能够放心使用右服务,而不用关心右服务如何实现的关键指标。我们将在第8章重点讨论SLA。
通过让每个服务都有清晰的所有权,团队可以只关注于它们所负责的模块,以及依赖服务所提供的API约定。这种职责隔离使得组织能够更容易容纳更多的团队,因为团队之间的耦合程度更加松散,所以团队之间的距离(不管是组织上的层级还是物理上的距离)也就无关紧要。只要双方保持着一致的约定,你就可以扩展组织的规模,创建出更大型、更复杂的应用程序。
规模收益
应用程序的不同部分在伸缩性上有着不同的需求。生成首页的组件比生成用户设置页面的组件会更频繁地被使用到。
通过在服务之间使用清晰的API和API约定,你可以独立决定和实现每个服务的伸缩性需求。这意味着如果首页是最经常被访问的页面,相对于管理用户设置页面的服务来说,你可以提供更多的硬件资源给生成首页的服务。
通过独立管理每个服务的伸缩性需求,可以实现以下事情:
通过与相关功能负责团队的密切合作,提供更加准确的可伸缩性。
将系统资源留给真正需要伸缩性的组件。
将伸缩性的决定权交回团队,因为它们才是最了解服务需求的人(服务所有者)。
基于服务的架构使得组织和应用程序变得更容易伸缩,并且能够伸缩到更大的规模。在下一章中,我们将更详细地介绍服务。