各个微服务的数据自主权

小窍门

此内容摘自电子书《适用于容器化 .NET 应用程序的 .NET 微服务体系结构》,可以在 .NET Docs 上获取,也可以下载免费的 PDF 以供离线阅读。

适用于容器化 .NET 应用程序的 .NET 微服务体系结构电子书封面缩略图。

微服务体系结构的一个重要规则是,每个微服务必须拥有其域数据和逻辑。 正如完整的应用程序拥有其逻辑和数据一样,每个微服务必须在自治生命周期下拥有其逻辑和数据,每个微服务都有独立的部署。

这意味着域的概念模型在子系统或微服务之间将有所不同。 考虑企业应用程序,其中客户关系管理(CRM)应用程序、事务性购买子系统和客户支持子系统每次调用唯一客户实体属性和数据,以及每个应用程序采用不同的边界上下文(BC)。

这一原则在 域驱动设计(DDD)中类似,其中每个 边界上下文 或自治子系统或服务必须拥有其域模型(数据加上逻辑和行为)。 每个 DDD 绑定上下文都与一个业务微服务(一个或多个服务)相关联。 下一部分将进一步详述关于边界上下文模式的重要观点。

另一方面,许多应用程序中使用的传统(单一数据)方法是拥有一个集中式数据库或一些数据库。 这通常是用于整个应用程序及其所有内部子系统的规范化 SQL 数据库,如图 4-7 所示。

显示两种数据库方法的关系图。

图 4-7. 数据主权比较:整体数据库与微服务

在传统方法中,在所有服务之间共享单个数据库,通常位于分层体系结构中。 在微服务方法中,每个微服务拥有其模型/数据。 集中式数据库方法最初看起来更简单,似乎允许重复使用不同子系统中的实体,使一切保持一致。 但现实情况是,最终你会遇到为许多不同子系统服务的巨型表,其中包含在大多数情况下并不需要的属性和列。 这相当于在进行短途徒步旅行、一天自驾游和学习地理知识时使用同一张自然地图。

具有单一关系数据库的单体应用程序具有两个重要优势: ACID 事务 和 SQL 语言,既能处理与应用程序相关的所有表和数据。 此方法提供了一种轻松编写查询的方法,用于合并来自多个表的数据。

但是,迁移到微服务体系结构时,数据访问会变得更加复杂。 即使在微服务或边界上下文中使用 ACID 事务时,也有必要考虑每个微服务拥有的数据是该微服务的专用数据,仅应通过其 API 端点(REST、gRPC、SOAP 等)以同步方式或通过消息传递(AMQP 或类似)以异步方式访问。

封装数据可确保微服务松散耦合,并且可以独立于彼此发展。 如果多个服务访问相同的数据,架构更新需要对所有服务进行协调更新。 这将破坏微服务生命周期的自主性。 但分布式数据结构意味着不能跨微服务进行单个 ACID 事务。 这反过来意味着,当业务流程跨越多个微服务时,必须使用最终一致性。 这比简单的 SQL 联接更难实现,因为不能在单独的数据库之间创建完整性约束或使用分布式事务,如稍后我们将介绍的那样。 同样,许多其他关系数据库功能在多个微服务中不可用。

更进一步,不同的微服务通常 使用不同类型的数据库 。 新式应用程序存储和处理各种类型的数据,关系数据库并不总是最佳选择。 对于某些用例,NoSQL 数据库(如 Azure CosmosDB 或 MongoDB)可能具有更方便的数据模型,并且比 SQL Server 或 Azure SQL 数据库等 SQL 数据库提供更好的性能和可伸缩性。 在其他情况下,关系数据库仍然是最佳方法。 因此,基于微服务的应用程序通常使用 SQL 和 NoSQL 数据库的混合,有时称为 polyglot 持久性 方法。

用于数据存储的分区的多语言持久性体系结构具有许多优势。 其中包括松散耦合的服务以及更好的性能、可伸缩性、成本和可管理性。 但是,它可能会引入一些分布式数据管理挑战,如本章后面的“识别域模型边界”中所述。

微服务与边界上下文模式之间的关系

微服务的概念派生自域驱动设计(DDD)中的边界上下文(BC)模式。 DDD 通过将模型划分为多个 BC 并明确其边界来处理大型模型。 每个 BC 必须有自己的模型和数据库;同样,每个微服务拥有其相关数据。 此外,每个 BC 通常都有自己的 无处不在语言 ,以帮助软件开发人员和域专家之间的通信。

这些术语(主要是域实体)在无处不在的语言中可以有不同的名称在不同的边界上下文中,即使不同的域实体共享相同的标识(即用于从存储中读取实体的唯一 ID)。 例如,在用户配置文件界定上下文中,用户域实体可能与买家域实体在订购界定上下文中共享标识。

因此,微服务类似于绑定上下文,但它还指定它是分布式服务。 它作为每个有限上下文的单独进程生成,并且必须使用前面所述的分布式协议,例如 HTTP/HTTPS、WebSocket 或 AMQP。 但是,绑定上下文模式不指定绑定上下文是分布式服务,还是只是整体部署应用程序中的逻辑边界(例如泛型子系统)。

务必强调,定义每个界定上下文的服务是一个不错的开端。 但是,你不必将设计局限于此。 有时,必须设计由多个物理服务组成的有限上下文或业务微服务。 但最终,-Bounded 上下文模式和微服务模式都密切相关。

DDD 通过获取分布式微服务形式的实际边界而从微服务中获益。 但是,不共享微服务间的模型这类想法也适用于界定上下文。

其他资源