如何处理CQRS中的读取模型

问题描述 投票:1回答:2

我们想在新设计中实现cqrs。我们在处理命令处理程序和读取模型时有一些疑问。我们理解在处理命令时我们应该对aggregateId采取乐观锁定。但是在处理readModel时应该考虑什么方法。我们应该锁定整个readModel还是在aggregateId上,或者在处理读取模型时永远不要锁定。

案例1.当锁定整个readmodel时 - >它是最安全的,但速度方面不好。

案例2 - 对aggregateId进行锁定。这里可能会出现两个问题。如果我们采取锁定aggregateId明智 - >然后如果读取模型服务器重新启动。它不知道从哪里开始。

案例3 - 永远不要锁定。在这种方法中,我认为数据可能处于崩溃状态。例如,如果生成订单插入事件并且通过一些工作流程/传奇,则也会发生订单更新事件。如果订单更新事件首先出现并且订单插入事件尚未处理,该怎么办?

希望我能解决我的问题。

domain-driven-design cqrs wolkenkit
2个回答
1
投票

如果您不在Readmodel中同时处理事件,则不需要锁定。当您在微服务中拥有可以轮询事件并按顺序处理它们的Readmodel的单个实例时就是这种情况。

如果你有一个同步Readmodel(即在与Writemodel / Aggregate相同的进程中),那么很可能你需要锁定。

需要记住的一件重要事情是,Readmodel很可能与Writemodel不同。在同一个Readmodel中可能会有很多事件被投射的Writemodel类型。例如,在电子商务商店中,您可以使用ListOfProducts来预测来自VendorProduct Aggregates的事件。这意味着,当我们谈论Readmodel时,我们不能简单地引用“Aggregate”,因为没有涉及单个Aggregate。在电子商务的情况下,当我们说“聚合”时,我们可能会引用Product Aggregate或Vendor Aggregate。

但要锁定什么?这取决于数据库技术。您应该锁定可以锁定的最小受影响的读取实体或集合。在由产品列表(读取实体,而不是聚合!)组成的Readmodel中,当只影响一个产品的事件时,您应该仅锁定该产品(即ProductTitleRenamed)。

如果某个事件影响了更多产品,那么您应该锁定整个集合。例如,VendorWasBlocked会影响所有产品(它应该删除该供应商的所有产品)。

对于具有非幂等副作用的事件,您需要锁定,对于Readmodel的updater在处理事件期间失败的情况,如果您想从其离开的位置重试/恢复。如果事件具有幂等副作用,则可以安全地重试。

为了知道在Readmodel失败的情况下从何处恢复,您可以在Readmodel内部存储最后处理的事件的序列。在这种情况下,如果实体更新成功,则还会保存最后处理的事件的序列。如果失败,则表示您未处理该事件。


1
投票

例如,如果生成订单插入事件并且通过一些工作流程/传奇,则也会发生订单更新事件。如果订单更新事件首先出现并且订单插入事件尚未处理,该怎么办?

如果您考虑对有序的事件序列进行轮询,而不是对无序通知做出反应,则读取模型通常更容易推理。

单个读取模型可能依赖于来自多个聚合的事件,因此聚合锁定不太可能是您最常见的答案。

这也意味着,如果我们进行轮询,我们需要跟踪多个数据流的位置。换句话说,我们的读取模型可能包含元数据,告诉我们每个源的使用版本。

锁定可能取决于后备存储/缓存的性质。但乐观的做法

  1. 阅读当前的表示
  2. 计算新的表示
  3. 比较和交换

再次,通常很容易推理。

© www.soinside.com 2019 - 2024. All rights reserved.