首页 文章

处理CQRS读取端的无序事件

提问于
浏览
7

我已经阅读了Jonathan Oliver关于处理无序事件的好帖子 .

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

我们使用的解决方案是将消息出列并将其置于“保持表”中,直到收到具有先前序列的所有消息 . 当收到所有先前的消息后,我们将所有消息从保留表中取出,并通过适当的处理程序依次运行它们 . 一旦所有处理程序都成功执行,我们将从保留表中删除消息并将更新提交给读取的模型 . 这适用于我们,因为域发布事件并使用适当的序列号标记它们 . 如果没有这个,下面的解决方案将变得更加困难 - 如果不是不可能的话 . 此解决方案使用关系数据库作为持久性存储机制,但我们没有使用存储引擎的任何关系方面 . 与此同时,所有这一切都有一个警告 . 如果消息2,3和4到达但消息1从未到达,则我们不会应用其中任何消息 . 只有在出现错误处理消息1或消息1以某种方式丢失时,才会出现这种情况 . 幸运的是,很容易纠正我们的消息处理程序中的任何错误并重新运行消息 . 或者,在丢失消息的情况下,直接从事件存储重建构建读取模型 .

得到了一些问题,尤其是关于他如何说我们总能向活动商店询问缺失的事件 .

  • CQRS的写入端是否必须将读取端的服务公开给"demand"重放事件?例如,如果没有收到事件1,但是有2,4,3,我们可以通过服务要求eventstore从1开始重新发布事件吗?

  • 此服务是否由CQRS的写入方负责?

  • How do we re-build the read model using this?

3 回答

  • 1

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

    一旦你检测到,你只是抛出异常 . 如果您的订户具有“重试”机制,它将尝试在一秒左右再次处理此事件 . 很有可能在此期间处理早期事件并且序列将是正确的 . 如果无序事件很少发生,这是一个解决方案 .

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

  • 0

    你在这里描述的是事件采购(ES) . 将命令模型发出的事件存储到持久存储 . 按事件类型,命令模型ID(聚合根id),命令模型类型(聚合根类型)重播存储的事件 . 这是ES的优势 . 您甚至可以稍后重播这些事件以生成新类型的查询模型 . 使用ES方法也可以用于具有UnitOfWork范围的应用程序事务 . 在提交时,发出的事件被持久化并分发给事件侦听器(QM维护服务) . 提交阶段的验证应该包含按db中的序列号检查并发访问 .

  • 0

    另一种方法是从(S1)提供您的阅读事件服务,使其只能为您的服务生成有序事件(S2) .

    例如,如果您有许多不同会话的事件加载,请在前端订购服务(O1)负责订单 . 它确保每个会话只有一个事件传递给(S1),并且只有当(S1)和(S2)都成功处理时(O1)才允许该会话的新事件传递给(S1) . 为了提高性能,也要排队等待 .

相关问题