处理CQRS读取端的乱序事件 [英] Handling out of order events in CQRS read side

查看:94
本文介绍了处理CQRS读取端的乱序事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了乔纳森·奥利弗(Jonathan Oliver)的这篇不错的文章,内容涉及处理乱序事件.

I've read this nice post from Jonathan Oliver about handling out of order events.

http://blog.jonathanoliver.com/cqrs-out-of-sequence-messages-and-read-models/

我们使用的解决方案是使一条消息出队,并将其放置在保存表"中,直到所有具有先前顺序的消息都被处理为止. 已收到.收到所有先前的消息后,我们将全部 消息从保留表中移出并依次通过 适当的处理程序.一旦所有处理程序都已执行 成功地,我们从保持表中删除消息并提交 读取模型的更新.

The solution that we use is to dequeue a message and to place it in a "holding table" until all messages with a previous sequence are received. When all previous messages have been received we take all messages out of the holding table and run them in sequence through the appropriate handlers. Once all handlers have been executed successfully, we remove the messages from the holding table and commit the updates to the read models.

这对我们有用,因为域发布了事件并对其进行了标记 带有适当的序列号.没有这个,解决方案 如果不是不可能的话,下面的难度会更大.

This works for us because the domain publishes events and marks them with the appropriate sequence number. Without this, the solution below would be much more difficult—if not impossible.

此解决方案使用关系数据库作为持久性存储 机制,但我们没有使用 存储引擎.同时,所有这些都需要注意. 如果消息2、3和4到达但消息1从未到达,则我们不应用 任何一位.仅当出现错误时,才发生这种情况 处理消息1或消息1是否丢失.幸运的是, 可以很容易地纠正我们的消息处理程序中的任何错误, 重新运行消息.或者,如果丢失了邮件,请重新构建 直接从事件存储中读取模型.

This solution is using a relational database as a persistence storage mechanism, but we’re not using any of the relational aspects of the storage engine. At the same time, there’s a caveat in all of this. If message 2, 3, and 4 arrive but message 1 never does, we don’t apply any of them. The scenario should only happen if there’s an error processing message 1 or if message 1 somehow gets lost. Fortunately, it’s easy enough to correct any errors in our message handlers and re-run the messages. Or, in the case of a lost message, to re-build the read models from the event store directly.

特别是关于他说我们如何可以总是向事件存储询问丢失事件的问题.

Got a few questions particularly about how he says we can always ask the event store for missing events.

  1. CQRS的写入端是否必须公开用于读取的服务 一边按需"重播事件?例如,如果事件1不是 收到,但是2、4、3可以通过 服务从1开始重新发布事件?
  2. 此服务由CQRS的写方负责吗?
  3. 我们如何以此来重建读取模型?
  1. Does the write side of CQRS have to expose a service for the read side to "demand" replaying of events? For example if event 1 was not received but but 2, 4, 3 have can we ask the eventstore through a service to republish events back starting from 1?
  2. Is this service the responsibility of the write side of CQRS?
  3. How do we re-build the read model using this?

推荐答案

如果有序列号,则可以检测到当前事件发生故障的情况,例如currentEventNumber!= lastReceivedEventNumber +1

If you have a sequence number, then you can detect a situation where current event is out of order, e.g. currentEventNumber != lastReceivedEventNumber + 1

一旦检测到,就抛出异常.如果您的订户具有重试"机制,它将尝试在大约一秒钟内再次处理此事件.在这段时间内,很有可能会处理较早的事件,并且顺序正确.如果乱序事件很少发生,这是一个解决方案.

Once you've detected that, you just throw an exception. If your subscriber has a mechanism for 'retries' it will try to process this event again in a second or so. There is a pretty good chance that during this time earlier events will be processed and sequence will be correct. This is a solution if out-of-order events are happening rarely.

如果您经常遇到这种情况,则需要实现全局锁定机制,该机制将允许顺序处理某些事件. 例如,我们在某些情况下使用MSSQL中的sp_getapplock来实现全局关键部分"行为.当分布式应用程序的多个部分需要的不仅仅是简单的锁时,Apache ZooKeeper提供了一个框架来处理甚至更复杂的情况.

If you are facing with this situation regularly, you need to implement global locking mechanism, which will allow certain events be processed sequentially. For example, we were using sp_getapplock in MSSQL to achieve global "critical section" behaviour in certain situations. Apache ZooKeeper offers a framework to deal with even more complicated scenarios when multiple parts of the distributed application require something more than a just simple lock.

这篇关于处理CQRS读取端的乱序事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆