有各种示例应用程序和框架实现CQRS + Event Sourcing体系结构,并且大多数描述使用事件处理程序从存储在事件存储中的域事件创建非规范化视图。
托管此体系结构的一个示例是作为web api,它接受写入端的命令并支持查询非规范化视图。此Web api可能会扩展到负载平衡服务器场中的许多计算机。
我的问题是读取模型事件处理程序在哪里托管?
可能的情况:
在单独的主机上的单个Windows服务中托管。 如果是这样,不会造成单点故障吗?这可能使部署变得复杂,但它确实保证了单个执行线程。缺点是读取模型可能会出现延迟增加的情况。
作为网络API自身的一部分托管。 例如,如果我使用EventStore进行事件存储和事件订阅处理,则会为每个单个事件触发多个处理程序(每个Web场进程中一个),从而导致处理程序中的争用他们试图读/写他们的阅读商店?或者,对于给定的聚合实例,我们是否保证在事件版本顺序中一次处理一个所有事件?
我倾向于方案2,因为它简化了部署,并且还支持需要同时监听事件的流程管理员。同样的情况,因为只有一个事件处理程序应该处理单个事件。
EventStore可以处理这种情况吗?其他人如何在最终一致的架构中处理事件处理?
修改
为了澄清,我正在谈论将事件数据提取到非规范化表中的过程,而不是读取那些用于" Q"在CQRS。
我想我正在寻找的是我们应该如何"实现和部署可以支持冗余和扩展的读模型/ sagas / etc的事件处理,当然假设事件处理是以幂等方式处理的。
我已经阅读了两个可能的解决方案,用于处理在事件存储中保存为事件的数据,但我不明白哪一个应该用于另一个。
活动巴士
事件总线/队列用于在保存事件后发布消息,通常由存储库实现。有兴趣的人(订阅者),例如阅读模型,或传奇/流程管理者,以某种方式使用公共汽车/队列""以幂等方式处理它。
如果队列是pub / sub,这意味着每个下游依赖项(读取模型,sagas等)每个只能支持一个进程来订阅队列。不止一个流程意味着每个流程处理相同的事件,然后竞争以使下游变更。幂等处理应该处理一致性/并发性问题。
如果队列是竞争消费者,我们至少可以在每个Web场节点中托管订户以实现冗余。虽然这需要每个下游依赖的队列;一个用于sagas /流程管理器,一个用于每个读取模型等,因此存储库必须发布到每个以便最终的一致性。
订阅/进料
订阅/订阅,其中感兴趣的各方(订阅者)按需读取事件流并从已知检查点获取事件以便处理为读取模型。
如果需要,这对于重新创建读取模型非常有用。但是,按照通常的发布/订阅模式,似乎每个下游依赖项只应使用一个订阅者进程。如果我们为同一个事件流注册多个订阅者,例如每个Web场节点中就有一个,他们都会尝试处理和更新相同的读取模型。
答案 0 :(得分:6)
在我们的项目中,我们使用基于订阅的预测。原因是:
考虑到这些原因,我们有基于订阅的单线程投影,可以做任何事情。您可以使用自己的检查点执行不同类型的投影,使用追赶订阅订阅事件存储。为了简单起见,我们将它们与许多其他东西一样托管在同一个进程中,但这个过程只能在一台机器上运行。如果我们想要横向扩展这个过程,我们将不得不接受订阅/预测。它可以轻松完成,因为除了读取模型DTO本身之外,这部分几乎没有其他模块的依赖性,无论如何都可以作为程序集共享。
通过使用订阅,您始终可以预测已提交的事件。如果投影出现问题,写入方面肯定是事实的来源并且仍然如此,您只需要修复投影并再次运行它。
我们有两个独立的 - 一个用于投影到读取模型,另一个用于将事件发布到消息总线。事实证明,这种结构非常有效。
答案 1 :(得分:0)
特别是对于EventStore,它们现在具有competing consumers,这是基于服务器的订阅,其中许多客户端可以订阅订阅组,但只有一个客户端获取消息。
听起来就像你所追求的那样,服务器场中的每个节点都可以订阅订阅组,接收消息的节点可以进行投影