微服务的优势不胜枚举。其他形式的分布式系统也具备部分相同的优势。然而,微服务往往在更大程度上实现了这些优势,主要是因为它在定义服务边界的方式上持有更加鲜明的立场。通过将信息隐藏和领域驱动设计的概念与分布式系统的强大功能相结合,微服务有助于获得比其他形式的分布式架构更显著的收益。
对于由多个互相协作的微服务组成的系统,我们可以在每个微服务内部使用不同的技术。这使得我们能够为不同类型的业务场景选择更合适的工具而不必遵循标准化、一刀切的方法,因为这种方法通常只能满足基础诉求。
如果系统中的某个部分需要较高性能,我们可以使用不同的技术栈以更好地达到所需的性能水平。我们还可以用不同的数据存储方式,对系统的不同部分进行增强。例如,在社交网络的业务场景下,可以将用户的交互存储在图数据库中,以图的方式反映社交的高度互联性质,但用户发布的帖子可以存储在文档数据库中,从而产生如图1-10所示的异构架构。
图1-10:微服务可以让你轻松使用不同的技术栈
通过使用微服务,我们还能够更快地尝试新技术,并了解技术的进步是否对系统有所帮助。尝试和采用新技术的最大障碍就是与之相关的风险。对于单体服务,如果想尝试一种新的编程语言、数据库或框架,任何变更都会影响大部分系统。有了一个由多个微服务组成的系统,就有了多个新地方来尝试这项新技术。我们可以选择风险可能最低的微服务并在其中使用新技术,因为我们可以控制潜在的负面影响。许多组织认为,这种更快地尝试和采用新技术的能力是一种真正的优势。
当然,多技术栈还是有成本的。一些组织选择对编程语言施加一些限制。例如,奈飞和 Twitter 主要使用 Java 虚拟机(Java Virtual Machine,JVM)作为运行时平台,因为这些公司非常了解该平台的性能和可靠性。他们还开发了适用于 JVM 的库和工具,使大规模运维变得更加容易,但是对 JVM 特定库的依赖使得引入非 Java 的服务或客户端就变得非常困难。但无论是 Twitter 还是奈飞,都并非只使用一种技术栈。
对消费者隐藏服务内部的技术实现可以让技术升级更加容易。例如,你的整个微服务架构可能基于 Spring Boot,但可以仅更改一个微服务的 JVM 版本或框架版本,从而更容易控制升级带来的风险。
提高应用系统健壮性的一个关键概念是舱壁(bulkhead)。系统的某个组件可能会发生故障,但只要该故障没有扩散,你就实现了故障隔离,且系统的其余部分还可以继续工作。在这里,服务边界成为显著的舱壁。而在单体系统中,如果发生故障,则一切都会停止工作。虽然在单体系统中,可以通过在多台机器上运行多个实例的方式来降低完全失败的可能性,但是采用微服务,我们就能够处理其中完全失败的服务,或相应地将服务降级,从而维护系统的可用性。
然而,我们仍需谨慎。为了确保微服务系统能够充分实现这种健壮性,我们需要处理这种由分布式技术所引入的新的故障源。网络会出现故障,机器也可能会。我们需要知道如何处理此类故障,以及这些故障将对软件的最终用户产生什么影响(如果有的话)。我曾与一些团队合作,发现他们由于没有足够重视这些问题,在将系统迁移到微服务架构后,系统的健壮性降低了。
对于一个大型的单体系统,在实施扩展时,需要对所有组件进行扩展。因为即便只是整个系统的一小部分在性能上受到了限制,但如果这部分功能被固化在一个庞大的单体系统里,我们仍然需要将所有组件作为一个整体来处理。然而,如果采用多个较小的服务,我们就可以只扩展那些需要扩展的服务,并可以在不那么强大的硬件上运行系统的其他部分,如图1-11所示。
图1-11:可以按需扩展微服务
在线时尚零售商 Gilt 正是出于这个原因采用了微服务。Gilt 从2007年开始使用单体 Rails 应用系统。到了2009年,它的系统已经无法应对被施加的负载。通过拆分系统的核心部分,Gilt 能够更好地应对流量高峰,如今它已拥有450多个微服务,每个微服务都在多台独立的机器上运行。
AWS 等公有云供应商提供了按需扩展系统资源的能力,我们甚至可以基于系统实际运行需要,应用这种按需扩展功能,这使我们能够更有效地控制成本。像这种几乎可以直接实现成本节约的架构方法并不常见。
最终,我们可以通过多种方式扩展应用系统,而微服务可以有效地支持这种扩展。我们将在第13章中更详细地探讨微服务的扩展性。
在有着百万代码行体量的单体系统中,即便是单行代码导致的变更,也必须通过重新部署整个系统才能发布。这种部署往往影响大、风险高。在实际操作中,出于担忧,我们会尽可能地回避少量变更导致的部署,从而降低发布变更的频率。但是,这意味着所做的更改会在多个不同版本上持续累积,直到最终进入生产环境,而这个新版本中包含着累积下来的大量变更。版本之间的差异越大,我们出错的风险就会越高。
如果使用微服务,我们就可以对单个服务进行更改,然后以独立于系统其余部分的方式进行部署。这让我们能够更快地部署代码。如果确实出现了问题,可以快速隔离这一单个服务,并轻松实现快速回滚。这也意味着可以更快地向客户推出我们的新功能。这是亚马逊和奈飞等组织使用这种架构的主要原因之一,即尽可能地消除妨碍软件快速发布的障碍。
我们中的许多人都经历过大型团队和大型代码库带来的问题,而如果团队还分布在不同地方,那么这些问题可能会更加严重。我们清楚,处理小规模代码库的小团队往往更有效率。
微服务可以让我们更好地保持架构和组织的一致性,最大限度地减少每个代码库上工作的人数,从而达到团队规模和生产力的最佳平衡点。我们还可以随着组织的变化来改变服务的所有权,使我们在未来也能够持续保持架构和组织的一致性。
分布式系统架构和面向服务架构的关键优势之一是,有机会复用已有的功能,而使用微服务可以让功能以不同的方式为不同的目的服务。当你在考虑消费者将如何使用所开发的软件时,这一点尤为重要。
狭隘点儿说,仅考虑桌面网站或移动应用的时代已经一去不复返了。现在,我们需要考虑的是,如何用五花八门的技术将能力组合起来,以支持桌面网站、原生移动应用、移动端页面、平板电脑应用或可穿戴设备。随着越来越多的组织从狭隘的渠道思维转向更全面的客户融合(customer engagement)概念,我们需要能够跟得上这种转变。
我们可以将采用微服务看作把系统中服务间的接缝主动开放给外部。随着环境的变化,可以使用不同的方式来构建应用。但是对于单体系统,通常只有一个可以从外部使用的粗粒度接缝。如果想拆分它以获得更有用的东西,大概率就需要一把锤子了。