1)域事件和事务一致性以及2)集成事件和最终一致性之间的关系是什么

时间:2018-09-29 13:42:10

标签: c# domain-driven-design microservices

我了解交易一致性和最终一致性之间的区别。假设我正在开发一个应用程序,其中有三个微服务,并且有一个消息总线,当集成事件引发时,它们在它们之间发送消息,这意味着最终的一致性。例如,微服务B发布了一个集成事件,而微服务A在两个小时后进行了处理,因为微服务B在事件发布时就关闭了,并且消息是持久的-很好。

我的理解方式;微服务内部应具有事务一致性-聚合A可能发布聚合B感兴趣的域事件,因此引发了一个域事件,并且对数据库的任何更新都在同一事务内执行。

我不了解CQRS如何适应这种事务一致性/最终一致性方案,因为:

  1. 我无法使用事务一致性,因为无法在同一事务内更新读取模型(NoSQL)和写入模型(SQL服务器)。
  2. 我无法使用消息总线,因为更新读取模型不是集成事件,即读取模型和写入模型包含在同一微服务中。

对于CQR​​S,我相信有两种选择:

  1. 如果在写端使用事件存储,则读端可以对其进行轮询-因为没有事件,因此可以解决此问题。
  2. 如果在写端使用事件日志/关系数据库,则会引发Domain事件以更新读端。

如果选择了选项二,那么我如何才能保证读取模型最终与写入模型同步?例如,引发事件时,读取模型可能会关闭。

3 个答案:

答案 0 :(得分:2)

CQRS通过在将DBMS系统用于只读系统时为您提供针对开放式锁的较低的脆弱性,从而符合最终一致性的概念。分隔命令和查询使您可以进行有效的读/写操作,而不管两者的可用性如何。

1)。如果由于乐观锁定而希望具有高可用性的端点,则不建议采用事务一致性。

2)。绝对可以使用消息总线来更新读取的模型,因为排队的概念与上下文间数据同步不是同义词。

答案 1 :(得分:0)

从技术上讲,聚合是DDD中原子性的单位,因此不必保证通过域事件进行通信的聚合之间的一致性。摘自Evan的书:

  

AGGREGATE是一组关联对象,我们将其视为   用于数据更改的单位...不变式,它们是   每当数据更改时必须维护的一致性规则   涉及AGGREGATE成员之间的关系。任何规则   跨度AGGREGATES不会始终保持最新   ...但是在AGGREGATE中应用的不变式将被强制执行   完成每笔交易。

但是,出于实际目的,我开发的大多数服务 do 都将域事件的处理包装在为处理初始请求而创建的同一环境事务中。分布式应用程序很难设计和调试,而不必担心诸如补偿服务中的动作之类的事情!

我目前正在使用MediatR库将域事件处理程序与生成它们的原始命令/请求处理程序分离。它具有与消息传递系统非常相似的发送/处理语义,并包括一个健壮的类似于中间件的管道,用于验证和预处理/后处理。

答案 2 :(得分:0)

如果选择了选项二,那么我如何保证读取模型最终与写入模型保持同步?

解决方案是您的两种选择的组合:

  • 在执行命令时引发域事件。

  • 将域事件存储在写入模型的事件存储区中。静态轻量级订阅者执行此任务。该事件存储在与执行命令相同的事务中。

  • 工作进程或批处理进程获取事件存储的事件,并将其通过消息队列发送。

  • 订户将其从队列中取出并更新读取模型。

这样,您就不会丢失任何事件。如果由于某种原因无法使用读取的模型,则工作人员将再次对事件进行重新处理。