微服务的数据管理模式

微服务的关键组件之一是如何管理和访问数据。与传统的单片或三层应用程序相比,执行此操作的方法有所不同。一些模式很常见,但其他模式是特定的,需要在纳入解决方案之前进行评估。在探索 CQRS(包括它与 CRUD 的区别)之前,我们将简要介绍一些用于微服务的常见数据库模式,最后,看看它如何与事件溯源相结合。

微服务的常见数据库模式

在微服务的上下文中使用数据库有多种模式。在本节中,我们将介绍一些,从最常见的模式之一开始。 

每个微服务的数据库

每个微服务都使用一个数据库,而不是“一刀切”,这有助于确保每个服务都可以根据数据存储、建模等的要求使用数据库。在某些情况下,关系数据库是最合适的,而其他用途案例将受益于键值甚至基于文档(JSON)的数据库。底层数据库的细节由特定于服务的 API 抽象出来,最终导致灵活且松散耦合的架构。 

API 组成

由于每个微服务模式的数据库,每个服务都有自己的数据库并公开其 API。 

API 组合模式引入了另一个抽象级别,其中 API 组合器组件负责查询各个服务的 API。这种分散收集类型的方法通过为客户端应用程序提供统一的接口来避免复杂性。 

佐贺

这是一种高级模式,有助于克服每个微服务模式的数据库引入的约束以及微服务架构的一般分布式特性。这些模式需要与多个服务(及其各自的数据库)进行交互,使得事务工作流(符合 ACID)难以实现。Saga 模式涉及协调多个本地(特定于服务)事务并执行补偿事务以在失败时撤消它们。 

命令查询职责分离和事件溯源

与 saga 模式一样,命令查询职责分离 (CQRS) 和事件溯源是涉及分离读取和写入路径的相对先进的技术。下一节将更多地讨论 CQRS 以及它如何与另一种广泛使用的技术——创建、读取、更新、删除 (CRUD) 进行比较。 

CQRS 和 CRUD

让我们对这些术语有一个基本的了解。 

CRUD

基于 CRUD 的解决方案通常用于实现简单的应用程序逻辑。以处理用户注册、列出用户、更新用户信息(启用/禁用)和删除用户的用户管理服务为例。CRUD 之所以如此吸引人,是因为它使用单一的数据存储并且易于理解,因此很容易采用常见的架构模式,例如基于 HTTP 的 REST(JSON 是一种广泛使用的数据格式)。 

CQRS

与基于 CRUD 的解决方案相比,CQRS 是关于使用不同的数据模型进行读取和写入操作——在单个数据库内或跨多个数据库。这允许独立管理应用程序的读/写部分。例如,可以为读/写操作使用单独的数据库表,或者利用只读副本来横向扩展读取繁重的应用程序。 

图 1:CQRS,相同或不同的数据存储

CRUD 和 CQRS:差异

让我们更多地了解 CQRS,并在此过程中通过检查各种特征来了解它与 CRUD 的不同之处。 

数据存储类型

如前所述,可以使用单个或多个数据存储实现 CQRS。在单个数据库的情况下,可能会使用诸如单独的读/写表和只读副本之类的技术。或者,可以利用不同的数据库来满足操作的读/写路径的特定要求——例如,可以使用具有 ACID 语义的关系数据库来处理中低写入工作负载并使用内存缓存(如Redis ) 来服务读取请求。 

同步或异步

CRUD 操作大多以同步方式执行,但根据编程语言和客户端库,可以在客户端进行异步实现。CQRS 也可以以同步方式实现,但这种情况很少见。因为 CQRS 涉及多个数据存储(相同或不同的数据库),它受益于读取​​模型异步更新以响应写入数据存储的更改的机制。例如,在 RDBMS 表中插入(或更新)的用户信息会导致 Redis 以低延迟读取高规模/容量。但这种方法迫使我们考虑另一个重要属性——一致性。 

一致性

由于 CRUD 系统本质上是同步的并且受益于 ACID 支持(在关系数据库中),它们获得了强一致性(几乎是免费的)。使用 CQRS 实现,由于其异步特性,架构需要接受最终一致性,并确保应用程序可以容忍读取(可能)过时的数据,即使它可能只是很短的一段时间。 

可扩展性

CQRS 解决方案可以利用多个数据存储并且可以异步操作,这一事实使它们更具可扩展性。例如,如果需要,利用单独的数据存储优化高读取量。CRUD 解决方案的可扩展性受到单一数据存储和同步操作模式的限制。 

复杂

这听起来很明显,使用 CQRS 模式来构建应用程序是相当复杂的。如前所述,可能需要使用多个数据存储,在它们之间实现异步通信,并处理最终一致性及其注意事项。CRUD 操作被很好地理解和广泛使用,因此通常有很好的支持,例如代码生成器、对象关系建模库等,这大大简化了开发过程。 

下表总结了这些差异: 

特征CQRSCRUD
数据存储类型单个或多个数据存储单一数据存储
同步或异步异步(大部分)同步
一致性最终一致性强一致性
可扩展性高的有限的
复杂高的相对较低

CQRS 和事件溯源——更好的结合?

通过事件溯源,CQRS(代表命令)中的“C”变得活跃起来。系统的写入部分现在负责将命令存储在事件存储中,而读取部分则全部是关于数据的非规范化形式——这种形式也称为物化视图,支持对 UI 或应用程序的特定查询。一个基于事件溯源和 CQRS 的解决方案可能在多个数据存储中具有多个这样的视图。通常,这些模式本身就由数据存储本身支持,例如PostgresCassandra等。

事件不是普通数据——它们代表系统中的动作;因此,写入模型利用了仅附加的、不可变的数据存储。有时,事件溯源解决方案还在写入路径中利用流平台,例如Apache Kafka,而不是传统的 SQL/NoSQL 数据库。 

图 2:事件溯源

让我们看一个简单的例子。想想像 Twitter 这样的应用程序中的有限功能子集——用户发送推文,互相关注,并查看他们关注的用户的推文。一种简单的解决方案是在用户发推文时同步更新关注者时间线。对于用户可以拥有数百万追随者的系统,这是不可扩展的。更好的方法是将其拆分为不同的部分,其中“发送推文”(命令)用作可以触发关注者的时间线更新的事件,这可以异步发生。然后,关注者可以看到推文,该推文将由解决方案的“查询”部分处理,并可能由不同的数据存储支持——系统必须容忍最终的一致性,这对于这个特定的用例是可以接受的。 

优点和缺点

事件溯源和 CQRS 确实为我们提供了很大的权力,但随之而来的是巨大的责任。如果没有复杂的数据模型,请坚持使用基于 CRUD 的解决方案来简化整体架构。 

事件溯源涉及以仅追加、不可变的方式捕获命令/事件(已更改系统)——这意味着如果存在重放“历史”数据以重建系统的某些/整个部分的可能性需要这样做。但是,这在实际场景中并不容易,并且需要很好地规划此类流程,以最大程度地减少停机时间和服务中断。如果应用程序没有如此密集的要求,最好避免事件溯源/CQRS。 

对于架构处理事件,可以构建多个应用程序来处理它们。例如,用户创建的事件可以触发发送电子邮件处理程序,而另一个处理程序可以处理不同的操作(并行)。同时,需要考虑错误处理、重试和最终一致性。请注意这些要求,如果应用程序不能容忍最终的一致性,请不要使用 CRQS/事件溯源。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wouderw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值