CQRS:读取端的ACID

时间:2017-09-14 08:17:48

标签: azure transactions cqrs consistency

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

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

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

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

2 个答案:

答案 0 :(得分:1)

  

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

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

  

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

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

  

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

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

答案 1 :(得分:1)

CQRS系统倾向于基于最终一致性的概念(虽然这不是必需的 - 如果可扩展性不是主要问题,则可以使用事务和ACID DB) 。通过最终一致性,在执行命令后,对任何特定视图的查询可能会显示:

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

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

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

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

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