c# - 1)领域事件和事务一致性与2)集成事件和最终一致性之间的关系是什么
问题描述
我理解事务一致性和最终一致性之间的区别。假设我正在开发一个应用程序,其中有三个微服务,并且有一个消息总线,当引发集成事件时,它会在它们之间发送消息,这意味着最终的一致性。例如,微服务 B 发布了一个集成事件,微服务 A 在两小时后处理它,因为微服务 B 在事件发布时已关闭并且消息是持久的 - 这很好。
我理解它的方式;微服务内部应该有事务一致性 - 聚合 A 可能会发布聚合 B 感兴趣的域事件,因此引发域事件并且对数据库的任何更新都在同一事务中执行。
我不明白 CQRS 如何适应这种事务一致性/最终一致性场景,因为:
- 我不能使用事务一致性,因为读取模型(NoSQL)和写入模型(SQL 服务器)不能在同一个事务中更新。
- 我不能使用消息总线,因为更新读取模型不是集成事件,即读取模型和写入模型包含在同一个微服务中。
对于 CQRS,我相信有两种选择:
- 如果在写入端使用事件存储,那么读取端可以轮询它——这解决了问题,因为没有事件。
- 如果将事件日志/关系数据库用于写入端,则会引发域事件以更新读取端。
如果选择了选项二,那么我如何保证读取模型最终与写入模型同步?例如,当事件引发时,读取模型可能会关闭。
解决方案
从技术上讲,聚合是 DDD 中的原子性单位,因此不需要保证通过域事件通信的聚合之间的一致性。从埃文的书中:
AGGREGATE 是一组关联对象,我们将其视为一个单元,用于数据更改。不变量是在数据更改时必须维护的一致性规则,将涉及 AGGREGATE 成员之间的关系。任何跨越 AGGREGATES 的规则都不会一直是最新的……但是在 AGGREGATE 中应用的不变量将在每个事务完成时强制执行。
然而,出于实际目的,我开发的大多数服务确实将域事件的处理包装在为处理初始请求而创建的同一个环境事务中。分布式应用程序很难设计和调试,而不必担心诸如补偿服务内部的操作之类的事情!
我目前正在使用MediatR库将域事件处理程序与生成它们的原始命令/请求处理程序分离。它具有与消息传递系统非常相似的发送/处理语义,并包括一个健壮的类似中间件的管道,用于验证和预处理/后处理。
推荐阅读
- git - 文件“A.gitgnore”没有忽略文件
- vue.js - Vue Moment 增加 6 个月并从现在开始使用
- javascript - 在两个之间更改字符串的颜色 | 符号
- python - 显示模式
- godot - 如何在 Godot 中像素化 2D 游戏?
- c++ - 在写入大量数据时,mmap() 比 ofstream() 慢
- python - 如何摆脱我的 Selenium 自动化弹出的 google cookie
- swift - 如何将 USDZ 下载为 Data 对象并将其转换回 USDZ?
- reactjs - FB 与 react native 集成时出错
- flutter - 如何进行测试分片或并行运行以实现颤振