微服务架构原理与开发实战
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.4.2 微服务架构的特点

1.1节的微服务定义大致反映出微服务架构的一些特点:微服务是小的服务;微服务是独立运行的;微服务的交互是轻量级的,是可以跨语言的;服务的设计是围绕业务的;微服务是可以自动部署的,有集中式的服务管理等。

但随着微服务的发展,它的定义是多变的,每个人在使用微服务架构时的做法都不完全一样,其中有很多很好的实践,有复杂的,也有简单的,似乎很难去界定谁对谁错,毕竟由于软件项目的独特性,每种实践都是在特定的需求和场景下产生的,因此不妨把目光放在它们的共同点上。此前有过无数人的大胆尝试和实践,我们可以通过分析来看看大多数人都在怎样做着微服务。

ThoughtWorks的Martin Fowler是业界的权威专家,他认为虽然很难给微服务的架构一个正确的定义,但可以尝试描述我们认为有合适标签的架构的共同特征。并非所有的微服务架构都具有所有的特征,但是Martin Fowler希望大多数微服务能具有大部分特征。最后,他总结了微服务的九大特征,成为当下这个松散的社区关于微服务的一个宽松的标准。

下面就来看看微服务的九大特征,如图1.8所示。

图1.8 微服务的九大特征

1. 服务组件化

组件简单来说就是一个可以独立更换和升级的软件单元,就像计算机的内存、显卡、硬盘一样,是可插拔的,而且更换和设计不会影响其他单元。在微服务架构设计中,我们将应用拆分为一个个独立的服务,这些服务像组件一样可以独立更换和升级。每个服务拥有独立的进程,可以独立开发和部署;每个服务可以拥有独立的存储,服务之间通过HTTP等轻量级的通信协议进行交互,而不是传统的嵌入式的方式。

2. 围绕业务组织团队

通常,传统的公司可能会按照技术去组建团队,如测试团队、前端开发团队、后端开发团队、数据库团队、运维团队等,但微服务本身的设计是围绕业务展开的,各个服务按照业务价值来划分边界,这样就导致了微服务的团队组织结构上是必须跨技术能力的,一个团队中可能需要包括各种能力的人,如前业务分析师、测试工程师、前端开发工程师、后端开发工程师、数据库工程师、UI设计师、运维工程师等。

当然,由于微服务小的设计理念,团队的规模不会很大,如亚马逊的“Two Pizza Team”原则,一个团队吃一餐饭只需两个披萨就够了。这样一个团队,工作中的内耗是很低的,因为团队的职责边界更加清晰,团队间沟通不畅或者推卸责任等现象将会得到改善。

3. 做产品而非项目

微服务架构中流行着一句话:“You build,you run it!”意思是你构建的应用,那么由你来负责运行它。

人们在传统的软件项目中,往往以一个做交付的方式来做项目,而不会考虑整个产品的运作方式或生命周期。例如,产品将需求交付给开发,开发将应用交付给测试,测试将构建好的版本交付给运维,运维负责将应用运行起来。

微服务架构的团队组织可以说是麻雀虽小五脏俱全,一个团队往往需要负责项目的全部阶段的工作,微服务团队更像是在做产品而非项目,大家需要关注整个产品的生命周期,负责各个阶段的各种工作,并且持续关注服务的运作情况,从而不断分析,来帮助客户提升业务价值,倡导开发运维一体化,现在很流行的DevOps等角色,也是在微服务流行趋势下所产生的。

4. 智能端点和哑管道

由于微服务本身分离的特点,它并不能像单体式架构那样通过本地的函数调用即可进行服务间的交互,那么选择一个好的远程调用的通信方式是关键。

在SOA中,有一些较好的实践,如在1.2.3节中提到的ESB就强调需要将调用逻辑放入沟通机制本身,各个端点遵循统一的标准,由企业服务总线来完成消息路由、编排和转换等功能。这会导致服务间的通信更加烦琐,笨重的调用方式在服务升级或更换时显得尤为吃力。所以,我们需要更加粗粒度、更加轻量的通信机制。

微服务社区更倾向于采用另一种方法:智能端点和哑管道。微服务在设计上不只是在意分离,还强调内聚,每个服务拥有自己的领域逻辑,就像是UNIX的管道设计一样。目前最常用的有两种协议:一种是带有资源API的HTTP请求,即人们常说的RESTful API请求;另一种是通过轻量级的消息总线,如使用RabbitMQ或ZeroMQ等来进行消息传递。

5. 去中心化治理

无论是单体式架构,还是SOA,似乎都需要定义一个统一的技术平台标准,但经验表明,这种做法并不好,不是每个问题都是钉子,不是每个解决方案都是锤子,每种技术平台都会有它的短板,一旦规定了统一的技术平台标准,在遇到它的短板时,开发者将感到十分痛苦。

微服务团队更提倡采用不同的方法或标准,使用正确的工具和技术来完成工作。通过轻量级的、粗粒度的通信机制,不同的服务不再需要中心化的技术平台标准,服务可以是不同语言、不同框架的,可以根据不同的业务场景需要来选择合适的技术。

6. 分散的数据管理

分散的数据管理十分符合微服务最初的定义,服务间是独立运行的,每个服务都可以拥有自己独立的存储。当然,关于去中心化数据管理,业界也有很多解决方案,如模型概念上的不同,可以抽象出不同的视图,可以使用领域驱动设计的方式(后面章节会介绍)将复杂的领域划分成不同的限界上下文,这有助于澄清业务边界,强化数据模型上的分离。

微服务除在概念模型上的分散策略之外,还分散了数据的存储决策,让每个服务管理自己的数据库,可以是相同的数据库技术的不同实现,也可以是完全不同的数据库系统。人们把这种方式称为“Polyglot Persistence”(多语言持久化)。

当然,这种做法也会带来一些弊端,如分布式事务等问题,往往需要通过额外的工作来保证事务的最终一致性,但是这丝毫不会阻碍其在微服务架构中的应用,微服务团队往往把这个问题的解决寄希望于服务拆分的合理性上。

7. 基础设施自动化

微服务由于小和分离的特点,往往一个大型复杂的项目运作需要部署很多服务,如果都是人工手动来完成这项工作,那么无疑将会耗费巨大的成本,而且人工容易出错,一旦出错,排查会十分费力,好在基础设施自动化技术在过去几年中发生了巨大的变化,特别是云技术、Docker和K8s等技术的发展,大大降低了构建、部署和运行软件的成本。

各种持续集成和持久交付的工具层出不穷,而微服务架构中就需要这样的服务或技术工具来保证服务的构建、部署和测试等工作可以做到自动化。

8. 容错设计

使用服务作为组件的结果就是需要设计的应用程序能够容忍服务的失败。由于服务提供者不可用,任务服务消费者调用此服务时都可能失败,因此服务消费者必须尽可能优雅地对此做出响应。

单体式架构在这方面似乎有一定的优势,由于都是本地函数调用,它无须引入额外的复杂代码就可达到优雅响应的目的,但任何事情都有其多面性,单体式架构的优点是系统复杂度降低了,但缺点也是毋庸置疑的。也就是说,如果服务不可用,可能会影响整个应用,致使其他无关的功能都不可用。

所以,微服务架构中一般最基本的做法是针对每个服务都进行弹性的监控和日志记录,这样能够保证在服务出现故障时快速地监控并加以恢复。有关断路器、当前吞吐量和延迟的信息监控等其他方式,在后续的章节中详细介绍。

9. 演进式设计

现在已经知道了很多微服设计的关键因素,不难看出,要设计一个完美的微服务架构,尤其是对于没有足够经验的团队来说,无疑是很难的。但从软件设计的思路来看,没有设计从一开始就是完美的。

所以,很多情况下,微服务从业者都会以演进的方式进行系统的设计,笔者在工作中也常被项目的业务分析师问道:为什么我看你们总在重构,就不能一开始写代码时把结构设计好吗?这时,笔者反而觉得这是软件设计好的表现,然后很耐心地和他解释软件设计的思路就是这样的。人们称其为演进式设计。

当然,重构也是需要条件的,开发人员应该能够控制应用程序的更改,而且不会降低变更速度。变更控制并不一定意味着改变,但可以通过正确的态度和工具,如单元测试、契约测试等,对软件进行频繁、快速和良好控制的更改。