如何托管Event Sourcing事件处理程序来构建读取模型?

Mar*_*ark 6 cqrs event-sourcing event-store get-event-store

存在实现CQRS +事件源架构的各种示例应用和框架,并且大多数描述使用事件处理器来从存储在事件存储中的域事件创建非规范化视图.

托管此体系结构的一个示例是作为web api,它接受写入端的命令并支持查询非规范化视图.此Web api可能会扩展到负载平衡服务器场中的许多计算机.

我的问题是读取模型事件处理程序托管在哪里?

可能的情况:

  1. 在单独的主机上托管在单一的Windows服务中. 如果是这样,那不会造成单点故障吗?这可能使部署复杂化,但它确实保证了单个执行线程.缺点是读取模型可能会出现延迟增加的情况.

  2. 作为web api本身的一部分托管. 如果我正在使用EventStore,例如,对于事件存储和事件订阅处理,将为每个单个事件触发多个处理程序(每个Web场进程中一个),从而在处理程序尝试读/写时引起争用到他们的读店?或者,对于给定的聚合实例,我们是否保证在事件版本顺序中一次处理一个所有事件?

我倾向于方案2,因为它简化了部署并且还支持需要也监听事件的流程管理器.虽然只有一个事件处理程序应该处理单个事件,但情况相同.

EventStore可以处理这种情况吗?其他人如何在最终一致的架构中处理事件处理?

编辑:

为了澄清,我在谈论将事件数据提取到非规范化表中的过程,而不是在CQRS中读取那些表中的"Q".

我想我正在寻找的是我们如何"应该"实现和部署可以支持冗余和扩展的读取模型/ sagas/etc的事件处理的选项,当然假设事件处理是以幂等方式处理的.

我已经阅读了两个可能的解决方案,用于处理在事件存储中保存为事件的数据,但我不明白哪个应该用于另一个.

活动巴士

事件总线/队列用于在保存事件后通常由存储库实现发布消息.感兴趣的各方(订阅者),例如阅读模型或传奇/流程管理者,以某种方式使用总线/队列来以幂等方式处理它.

如果队列是pub/sub,这意味着每个下游依赖项(读取模型,sagas等)每个只能支持一个进程来订阅队列.不止一个流程意味着每个流程处理相同的事件,然后竞争以使下游变更.幂等处理应该处理一致性/并发性问题.

如果队列是竞争消费者,我们至少可以在每个Web场节点中托管订户以实现冗余.虽然这需要每个下游依赖的队列; 一个用于sagas /流程管理器,一个用于每个读取模型等,因此存储库必须发布到每个以获得最终的一致性.

认购/饲料

订阅/馈送,其中感兴趣的各方(订户)按需读取事件流并从已知检查点获取事件以便处理成读取模型.

如果需要,这对于重新创建读取模型非常有用.但是,按照通常的发布/订阅模式,似乎每个下游依赖项只应使用一个订阅者进程.如果我们为同一事件流注册多个订户,例如每个Web场节点中有一个订户,则他们都将尝试处理和更新相同的相应读取模型.

Ale*_*rev 6

在我们的项目中,我们使用基于订阅的预测.原因是:

  • 承诺写入方必须是事务性的,如果您使用两个基础结构(事件存储和消息总线),则必须开始使用DTC,否则您可能会将事件保存到存储但不会发布到总线,或者相反,取决于您的实施.DTC和两阶段提交是令人讨厌的事情,你不想这样做
  • 事件通常在消息总线中发布(我们也通过订阅来发布),用于不同有界上下文之间的事件驱动通信.如果您使用消息订阅者更新您的读取模型,当您决定重建读取模型时,您的其他订阅者也将获得这些消息,这将使系统处于无效状态.我想你已经考虑过这个问题,因为你说每个发布的消息类型只能有一个订阅者.
  • 消息总线消费者无法保证消息顺序,这可能会使您的读取模型变得混乱.
  • 消息使用者通常通过将消息发送回队列(通常在队列末尾)进行重试来处理重试.这意味着您的活动可能会严重失灵.此外,通常在经过一些重试之后,消息使用者放弃有害消息并将其放入某些DLQ.如果这是您的预测,这将意味着将忽略一个更新,而其他更新将被处理.这意味着您的读取模型将处于不一致(无效)状态.

考虑到这些原因,我们有基于订阅的单线程投影,可以做任何事情.您可以使用自己的检查点执行不同类型的投影,使用追赶订阅订阅事件存储.为了简单起见,我们将它们与许多其他东西一样托管在同一个进程中,但这个过程只能在一台机器上运行.如果我们想要横向扩展这个过程,我们将不得不接受订阅/预测.它可以很容易地完成,因为除了读取模型DTO本身之外,这部分几乎没有其他模块的依赖性,无论如何它都可以作为程序集共享.

通过使用订阅,您始终可以预测已提交的事件.如果投影出现问题,写入方面肯定是事实的来源并且仍然如此,您只需要修复投影并再次运行它.

我们有两个独立的 - 一个用于投影到读模型,另一个用于将事件发布到消息总线.事实证明,这种结构非常有效.