微服务体系结构的一个重要规则是,每个微服务必须拥有其域数据和逻辑。正如完整的应用程序拥有自己的逻辑和数据一样,每个微服务也必须在自主生命周期中拥有自己的逻辑和数据,每个微服务都有独立的部署。
这意味着域的概念模型在子系统或微服务之间会有所不同。考虑企业应用程序,其中客户关系管理(CRM)应用程序、事务性采购子系统和客户支持子系统各自调用唯一的客户实体属性和数据,并且每个应用程序使用不同的有界上下文(BC)。
这一原则在领域驱动设计(DDD)中类似,每个有界上下文或自治子系统或服务都必须拥有自己的领域模型(数据加上逻辑和行为)。每个限定于DDD的上下文都与一个业务微服务(一个或多个服务)相关。关于有界上下文模式的这一点将在下一节中展开。
另一方面,在许多应用程序中使用的传统(单片数据)方法是有一个单一的集中式数据库或只有几个数据库。这通常是一个标准化的SQL数据库,用于整个应用程序及其所有内部子系统,如图4-7所示。
传统方式数据管理
微服务的数据方式
在传统方法中,所有服务共享一个数据库,通常是在分层体系结构中。在微服务方法中,每个微服务都拥有其模型/数据。集中式数据库方法最初看起来更简单,似乎可以重用不同子系统中的实体,使所有内容保持一致。但实际情况是,最终会出现大量的表,这些表服务于许多不同的子系统,其中包括在大多数情况下不需要的属性和列。这就像试图使用相同的物理地图徒步走一小段路,坐一天的汽车旅行,学习地理知识。
通常只有一个关系数据库的单片应用程序有两个重要的好处:ACID事务和SQL语言,它们都可以跨与应用程序相关的所有表和数据工作。这种方法提供了一种轻松编写查询的方法,该查询组合来自多个表的数据。
然而,当您转到微服务体系结构时,数据访问变得更加复杂。即使在微服务或有界上下文中使用ACID事务,也必须考虑每个微服务拥有的数据是该微服务的私有数据,并且只能通过其API端点(REST、gRPC、SOAP等)同步访问,或通过消息传递(AMQP或类似)异步访问。
封装这些数据可以确保微服务是松散耦合的,并且可以彼此独立地发展。如果多个服务访问同一数据,架构更新将需要对所有服务进行协调更新。这将打破微服务生命周期的自主性。但是分布式数据结构意味着您不能跨微服务进行单个ACID事务。这反过来意味着您必须在业务流程跨越多个微服务时使用最终一致性。这比简单的SQL连接更难实现,因为您不能创建完整性约束或在单独的数据库之间使用分布式事务,我们稍后将解释这一点。类似地,许多其他关系数据库特性在多个微服务中不可用。
更进一步说,不同的微服务通常使用不同类型的数据库。现代应用程序存储和处理各种类型的数据,关系数据库并不总是最佳选择。对于某些用例,NoSQL数据库(如Azure CosmosDB或MongoDB)可能比SQL数据库(如SQL Server或Azure SQL数据库)具有更方便的数据模型,并提供更好的性能和可伸缩性。在其他情况下,关系数据库仍然是最好的方法。因此,基于微服务的应用程序通常使用SQL和NoSQL数据库的混合,这有时被称为polyglot持久化方法。
用于数据存储的分区多时隙持久化体系结构有许多好处。其中包括松散耦合的服务和更好的性能、可伸缩性、成本和可管理性。但是,它可以引入一些分布式数据管理挑战,如本章后面的“确定域模型边界”中所述。
微服务与有界上下文模式的关系
微服务的概念源自域驱动设计(DDD)中的有界上下文(BC)模式。DDD通过将大型模型划分为多个bc并明确它们的边界来处理它们。每个BC都必须有自己的模型和数据库;同样,每个微服务都拥有自己的相关数据。此外,每个BC通常都有自己的通用语言来帮助软件开发人员和领域专家之间的通信。
泛在语言中的这些术语(主要是域实体)在不同的有界上下文中可以有不同的名称,即使不同的域实体共享相同的标识(即用于从存储中读取实体的唯一ID)。例如,在用户配置文件有界上下文中,用户域实体可以在顺序有界上下文中与买方域实体共享标识。
因此,微服务就像一个有界上下文,但它也指定它是一个分布式服务。它被构建为每个有界上下文的单独进程,并且必须使用前面提到的分布式协议,如HTTP/HTTP s、WebSockets或AMQP。然而,有界上下文模式并没有指定有界上下文是分布式服务还是仅仅是单片部署应用程序中的逻辑边界(如通用子系统)。
需要强调的是,为每个有界上下文定义服务是一个很好的起点。但你不必把你的设计局限于此。有时,必须设计由多个物理服务组成的有界上下文或业务微服务。但归根结底,模式限制上下文和微服务都是密切相关的。
DDD通过以分布式微服务的形式获得真正的边界而从微服务中获益。但是,在有限的上下文中,不在微服务之间共享模型等想法也是您所希望的。
额外资源
- 克里斯·理查森 模式:每个服务的数据库
- https://microservices.io/patterns/data/database-per-service.html
- 马丁·福勒: 边界上下文
- https://martinfowler.com/bliki/BoundedContext.html
- 马丁·福勒 :多语言持久性
- https://martinfowler.com/bliki/PolyglotPersistence.html
- 阿尔贝托·布兰多利尼:基于上下文映射的策略域驱动设计
- https://www.infoq.com/articles/ddd-contextmapping网站