我正在尝试了解有关 CQRS 和事件溯源(事件存储)的更多信息。
我的理解是,在这种情况下通常不使用消息队列/总线——消息总线可用于促进微服务之间的通信,但它通常不专门用于 CQRS。然而,我目前的看法是,消息总线将非常有用,可以保证读取模型最终同步,从而实现最终一致性,例如当托管读取模型数据库的服务器重新联机时。
据我了解,CQRS 通常可以接受最终一致性。我的问题是;读取端如何知道它与写入端不同步?例如,假设每天在事件存储中创建了 2,000,000 个事件,并且有 1,999,050 个事件也写入了读取存储。剩余的 950 个事件没有被写入,因为某个地方的软件错误或者因为托管读取模型的服务器离线了几秒钟等。最终一致性在这里如何发挥作用?应用程序如何知道重播一天结束时丢失的 950 个事件或由于 10 分钟前的停机而丢失的 x 个事件?
我在过去一周左右的时间里读过这里的问题,其中讨论了从事件存储中重播的消息,例如这个:CQRS - 读取端的事件重播 https://stackoverflow.com/questions/32818395/cqrs-event-replay-for-read-side,但是没有人谈论这是如何完成的。我是否需要设置每天运行一次并重播自计划任务上次成功之日起创建的所有事件的计划任务?有更优雅的方法吗?
根据需求,我在项目中使用了两种方法:
-
同步、进程中阅读模型。事件被持久化后,在相同的请求生命周期内,在相同的进程中,Readmodels 将被提供这些事件。如果 Readmodel 失败(错误或可捕获的错误/异常),则会记录错误,并且会跳过 Readmodel,并向下一个 Readmodel 提供事件等。然后遵循 Sagas,这可能会生成生成更多事件的命令,并重复该循环。
当业务可以接受 Readmodel 失败的影响时,当 Readmodel 数据的准备情况比失败风险更重要时,我会使用这种方法。例如,他们希望数据立即在 UI 中可用。
错误日志应该可以在某些管理面板上轻松访问,以便在客户端报告写入/命令和读取/查询之间不一致的情况下有人会查看它。
如果您的 Readmodel 相互耦合,即一个 Readmodel 需要来自另一个规范 Readmodel 的数据,这也适用。虽然这看起来很糟糕,但事实并非如此,这总是要看情况。在某些情况下,您需要用弹性来交换更新程序代码/逻辑重复。
-
异步,在另一个进程中读取模型更新程序。当我将 Readmodel 与其他 Readmodel 完全分离时,即 Readmodel 的失败不会导致整个读取端崩溃时,就会使用此方法;或者当 Readmodel 需要另一种不同于整体的语言时。基本上这是一个微服务。当 Readmodel 内部发生不良情况时,有必要通知一些权威的更高级别组件,即通过电子邮件或短信或其他方式通知管理员。
Readmodel 还应该有一个状态面板,其中包含有关它已处理的事件的各种指标、是否存在间隙、是否存在错误或警告;它还应该有一个命令面板,管理员可以随时重建它,最好不要系统停机。
在任何方法中,读取模型都应该易于重建。
您如何选择拉式方法和推式方法?您会使用带有推送(事件)的消息队列吗
我更喜欢基于拉动的方法,因为:
- 它不使用另一个有状态组件,例如消息队列,另一个必须管理的组件,它会消耗资源并且可能(因此会)失败
- 每个 Readmodel 以它想要的速率消耗事件
- 每个 Readmodel 都可以随时轻松更改其消耗的事件类型
- 通过从一开始请求所有事件,每个 Readmodel 都可以随时轻松重建
- 事件的顺序与事实的来源完全相同,因为你从事实的来源中提取信息
在某些情况下我会选择消息队列:
- 即使事件存储不存在,您也需要事件可用
- 你需要竞争/平行的消费者
- 您不想跟踪您消费了哪些消息;当它们被消耗时,它们会自动从队列中删除
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)