我了解交易一致性和最终一致性之间的区别。假设我正在开发一个应用程序,其中有三个微服务,并且有一个消息总线,当集成事件引发时,它们在它们之间发送消息,这意味着最终的一致性。例如,微服务B发布了一个集成事件,而微服务A在两个小时后进行了处理,因为微服务B在事件发布时就关闭了,并且消息是持久的-很好。
我的理解方式;微服务内部应具有事务一致性-聚合A可能发布聚合B感兴趣的域事件,因此引发了一个域事件,并且对数据库的任何更新都在同一事务内执行。
我不了解CQRS如何适应这种事务一致性/最终一致性方案,因为:
对于CQRS,我相信有两种选择:
如果选择了选项二,那么我如何才能保证读取模型最终与写入模型同步?例如,引发事件时,读取模型可能会关闭。
答案 0 :(得分:2)
CQRS通过在将DBMS系统用于只读系统时为您提供针对开放式锁的较低的脆弱性,从而符合最终一致性的概念。分隔命令和查询使您可以进行有效的读/写操作,而不管两者的可用性如何。
1)。如果由于乐观锁定而希望具有高可用性的端点,则不建议采用事务一致性。
2)。绝对可以使用消息总线来更新读取的模型,因为排队的概念与上下文间数据同步不是同义词。
答案 1 :(得分:0)
从技术上讲,聚合是DDD中原子性的单位,因此不必保证通过域事件进行通信的聚合之间的一致性。摘自Evan的书:
AGGREGATE是一组关联对象,我们将其视为 用于数据更改的单位...不变式,它们是 每当数据更改时必须维护的一致性规则 涉及AGGREGATE成员之间的关系。任何规则 跨度AGGREGATES不会始终保持最新 ...但是在AGGREGATE中应用的不变式将被强制执行 完成每笔交易。
但是,出于实际目的,我开发的大多数服务 do 都将域事件的处理包装在为处理初始请求而创建的同一环境事务中。分布式应用程序很难设计和调试,而不必担心诸如补偿服务中的动作之类的事情!
我目前正在使用MediatR库将域事件处理程序与生成它们的原始命令/请求处理程序分离。它具有与消息传递系统非常相似的发送/处理语义,并包括一个健壮的类似于中间件的管道,用于验证和预处理/后处理。
答案 2 :(得分:0)
如果选择了选项二,那么我如何保证读取模型最终与写入模型保持同步?
解决方案是您的两种选择的组合:
在执行命令时引发域事件。
将域事件存储在写入模型的事件存储区中。静态轻量级订阅者执行此任务。该事件存储在与执行命令相同的事务中。
工作进程或批处理进程获取事件存储的事件,并将其通过消息队列发送。
订户将其从队列中取出并更新读取模型。
这样,您就不会丢失任何事件。如果由于某种原因无法使用读取的模型,则工作人员将再次对事件进行重新处理。