【问题标题】:CQRS: ACID on Read-SideCQRS:读取端的 ACID
【发布时间】:2017-09-14 08:17:47
【问题描述】:

我经常读到 CQRS 的一大优势是在读取端具有非规范化数据。例如。可以存储冗余的数据字段和子对象以避免连接。但这也意味着单个事件可能会导致读取端的多个更新操作,因为实体的状态更改必须反映在多个读取端位置。

这是否意味着您需要在读取端支持原子事务? 许多 NoSQL 数据库只支持一个集合或一个分区内的事务。

基于 CQRS 的系统在现实生活中如何处理?

  • 他们是否在读取端使用 SQL 数据库?
  • 他们是否只使用非冗余数据?那么,为什么首先要有一个读取存储呢?
  • 是否有出色的数据库技术支持云中的原子事务?

【问题讨论】:

    标签: azure transactions cqrs consistency


    【解决方案1】:

    这是否意味着您需要在读取端支持原子事务?

    不,不一定,但您需要防止并发更新。

    他们是否在读取端使用 SQL 数据库?

    在我的最新项目中,我的大部分读取模型都使用 MongoDB。这个数据库没有事务支持,但我不需要,因为我使用乐观锁定。我写了一篇关于此的文章here,并附有一个 PHP 示例。这个想法是我通过使用版本(作为唯一索引)检测并发更新并重试最后一个。

    他们是否只使用非冗余数据?那么,为什么首先要有一个读取存储呢?

    我使用完整的数据非规范化。这意味着我在一个文档中拥有特定视图所需的所有信息。

    【讨论】:

    • 谢谢。我得出的结论是,只要读取端操作按顺序处理并且是幂等的,就可以重试它们。只要事件处理程序没有报告成功,这些事件就会被标记为未处理。
    • @mbnx 这还取决于您如何更新读取模型(读取模型包含事件处理程序和读取实体)。如果您依赖数据库来更新单个属性,那么您将不需要锁定,但它会破坏读取实体封装;如果您加载读取实体,则在其上应用事件然后将读取实体持久化,然后您需要锁定(乐观或悲观)。
    【解决方案2】:

    CQRS 系统倾向于基于最终一致性的概念(尽管这不是必需的 - 如果可伸缩性不是主要问题,替代方法是使用事务和 ACID DB) .在最终一致性的情况下,执行命令后,对任何特定视图的查询可能会看到:

    • 预命令状态
    • 命令后状态

    最终,所有视图都将使用命令后状态进行更新。这需要多长时间取决于负载和扩展、软件升级部署方法等。您的要求可能需要特定读取端的最大延迟,这显然会影响您对软件更新所采用的工程方法等。

    最终一致性对客户端代码有影响。通常,每个读取端“行”(文档/行等,取决于数据库的类型)将包括用于构建它的适用聚合的最新版本号。这意味着客户端可以轮询它期望更新的行的读取端查询服务,直到聚合版本版本返回递增,然后它知道查询结果包括它发送的命令的更改。 (轮询的替代方法包括网络套接字 - 读取端代码需要为每次更新触发通知)。

    处理并发是另一个与 ACID 相关的问题 - 这里的选项包括:

    • 乐观并发
    • 单线程和进程处理更新每个读取端
    • 在读取端对“行”进行分区,每个“行”仅由单个进程 + 线程更新
    • 确保一次只更新一个“行”的任何其他方式

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-02
      • 1970-01-01
      • 2017-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多