Domain driven design 如何在CQRS中处理读取模型

Domain driven design 如何在CQRS中处理读取模型,domain-driven-design,cqrs,wolkenkit,Domain Driven Design,Cqrs,Wolkenkit,我们希望在新设计中实现CQR。在处理命令处理程序和读取模型方面,我们有一些疑问。我们了解到,在处理命令时,我们应该乐观地锁定aggregateId。但在处理readModels时应该考虑什么方法。我们应该锁定整个readModel还是aggregateId,或者在处理readModel时永远不要锁定 案例1。当锁定整个readmodel->时,它是最安全的,但速度不好 案例2-锁定目标。这里可能出现两个问题。如果我们使用lock aggregateId wise->,那么如果读取模型服务器重新启

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

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

案例2-锁定目标。这里可能出现两个问题。如果我们使用lock aggregateId wise->,那么如果读取模型服务器重新启动该怎么办。它不知道从哪里开始

案例3-切勿使用锁。在这种方法中,我认为数据可能处于错误状态。例如,假设生成了订单插入事件,经过一些工作流/传奇,订单更新事件也发生了。若订单更新事件先出现,而订单插入事件尚未处理,该怎么办

希望我能解决我的问题

例如,假设生成了订单插入事件,经过一些工作流/传奇,订单更新事件也发生了。若订单更新事件先出现,而订单插入事件尚未处理,该怎么办

阅读模型通常更容易推理,如果您考虑它们轮询有序的事件序列,而不是对无序的通知作出反应

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

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

锁定可能取决于备份存储/缓存的性质。但这是一种乐观的态度

  • 读取当前表示
  • 计算新的表示
  • 比较和交换

  • 同样,通常很容易推理。

    如果在Readmodel中不同时处理事件,则不需要锁。当您拥有Readmodel的单个实例(可能在Microservice中)时,就会出现这种情况,该实例轮询事件并按顺序处理它们

    如果您有一个同步Readmodel(即与Writemodel/Aggregate处于同一进程中),那么很可能需要锁定

    需要记住的一点是,Readmodel很可能与Writemodel不同。可能有许多Writemodel类型的事件被投影到同一Readmodel中。例如,在电子商务商店中,您可以有一个
    产品列表
    ,该列表从
    供应商
    产品
    集合中投影事件。这意味着,当我们谈论Readmodel时,我们不能简单地提到“聚合”,因为没有涉及单个聚合。就电子商务而言,当我们说“聚合”时,我们可能指的是
    产品
    聚合或
    供应商
    聚合

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

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

    对于具有非幂等副作用的事件,如果您希望从其离开的位置重试/恢复,则需要锁定Readmodel的更新程序在事件处理过程中失败的情况。如果事件具有幂等副作用,则可以安全重试


    为了知道在Readmodel发生故障时从何处恢复,您可以在Readmodel中存储上次处理事件的序列。在这种情况下,如果实体更新成功,则最后处理的事件序列也会保存。如果失败,则您知道事件未被处理。

    这有关系吗?当使用CQR时,您通常在最终一致性的假设下工作。您通常将事件泵入一个队列,这样可以保证另一个工作者的执行顺序,从队列中获取项目并更新读取存储。如果在一个请求中,订单似乎尚未关闭或更新,通常情况下也不会那么糟糕,因为读取存储只是信息性的。您的权威存储是写入存储(用于通过重播事件填充聚合)readStore不仅仅是信息存储,我认为您的所有UI数据都来自ReadModel,而不是聚合(写入模型)。假设我们有多个工人正在处理事件总线。一名工人已弹出“下单”事件。正在处理,同时另一个工作人员弹出orderUpdated事件。现在,若第一个Worker还并没有完成订单的插入,那个么就会出现问题。我们正在通过总线或流序列化读取模型更新。如果您有一个从流中读取事件的工作进程,并且应用于读取模型,那么您不需要锁。谢谢Constantin。假设发生了两个订单事件。现在在read模型中,两个实体都是独立的。但当readModel处理事件时,应将二阶放置事件,等待直到一阶放置事件完全处理,其他明智的readModel可以;如果我们需要重新启动服务器,请不要保留它已处理的事件的状态。我们实际上正在处理异步的nodejs。@这取决于RohitBansal。如果序列化事件处理(如果等待),则必须只跟踪最后处理的事件。如果您没有序列化并并行执行,那么您应该存储您拥有的所有事件ID