有各种示例应用程序和框架实现CQRS +事件溯源架构,并且大多数都描述了使用事件处理程序从事件存储中创建非规范化视图。其中一种托管此架构的方法是将其作为Web API,接受命令以进行写操作,并支持查询非规范化视图。 这个Web API很可能会在负载平衡的许多计算机中扩展。
我的问题是非规范化模型事件处理程序托管在哪里?
可能的情况:
我想要的是关于如何实现和部署事件处理的选项,以支持冗余和扩展,假设事件的处理以幂等方式处理。
我已经阅读了两种处理保存为事件的数据的可能解决方案,但我不知道应该使用哪一种。
事件总线
事件总线/队列用于在保存事件后发布消息,通常由存储库实现。感兴趣的各方(订阅者),例如读模型或saga /流程管理器,以某种方式使用总线/队列以幂等方式处理它。
如果队列是发布/订阅,则意味着每个下游依赖项(读模型、saga等)只能支持一个进程订阅队列。多个进程意味着每个进程都会处理相同的事件,然后竞争使更改向下游传播。幂等处理应该解决一致性/并发问题。
如果队列是竞争消费者,我们至少可以在每个 Web Farm 节点上托管订阅者以实现冗余。虽然这需要为每个下游依赖项设置一个队列;一个用于 saga/process manager,一个用于每个读模型等,因此仓库必须向每个队列发布以实现最终一致性。
订阅/源
订阅/源是感兴趣的方(订阅者)按需读取事件流,并从已知检查点获取事件以处理成为读模型的方式。
如果需要重新创建读模型,则看起来很不错。但是,按照通常的发布/订阅模式,似乎应该仅使用每个下游依赖项的一个订阅者进程。例如,在每个 Web Farm 节点中注册多个订阅者,它们都将尝试处理并更新相同的读模型。
我的问题是非规范化模型事件处理程序托管在哪里?
可能的情况:
托管在单个窗口服务中,位于不同的主机上。 如果是这样,那么这不会创建单点故障吗?这可能会使部署复杂化,但它确保了单个执行线程。缺点是读模型可能会表现出增加的延迟。
作为Web API本身的一部分托管。 例如,如果我使用EventStore进行事件存储和事件订阅处理,那么是否会为每个单个事件触发多个处理程序(在每个Web农场进程中一个),从而在处理程序中引起争用,因为它们尝试读/写其读取存储?或者我们保证对于给定的聚合实例,其所有事件将按事件版本顺序逐个处理?
我倾向于方案2,因为它简化了部署,并且还支持需要同时侦听事件的流程管理器。不过情况相同,只有一个事件处理程序应该处理单个事件。
EventStore能处理这种情况吗?其他人如何处理最终一致性架构中的事件处理?
编辑:
为了澄清,我谈论的是将事件数据提取到非规范化表中的过程,而不是读取这些表以进行CQRS中的“Q”。我想要的是关于如何实现和部署事件处理的选项,以支持冗余和扩展,假设事件的处理以幂等方式处理。
我已经阅读了两种处理保存为事件的数据的可能解决方案,但我不知道应该使用哪一种。
事件总线
事件总线/队列用于在保存事件后发布消息,通常由存储库实现。感兴趣的各方(订阅者),例如读模型或saga /流程管理器,以某种方式使用总线/队列以幂等方式处理它。
如果队列是发布/订阅,则意味着每个下游依赖项(读模型、saga等)只能支持一个进程订阅队列。多个进程意味着每个进程都会处理相同的事件,然后竞争使更改向下游传播。幂等处理应该解决一致性/并发问题。
如果队列是竞争消费者,我们至少可以在每个 Web Farm 节点上托管订阅者以实现冗余。虽然这需要为每个下游依赖项设置一个队列;一个用于 saga/process manager,一个用于每个读模型等,因此仓库必须向每个队列发布以实现最终一致性。
订阅/源
订阅/源是感兴趣的方(订阅者)按需读取事件流,并从已知检查点获取事件以处理成为读模型的方式。
如果需要重新创建读模型,则看起来很不错。但是,按照通常的发布/订阅模式,似乎应该仅使用每个下游依赖项的一个订阅者进程。例如,在每个 Web Farm 节点中注册多个订阅者,它们都将尝试处理并更新相同的读模型。