Architecture 利用NServiceBus实现多线程CQRS

Architecture 利用NServiceBus实现多线程CQRS,architecture,nservicebus,cqrs,Architecture,Nservicebus,Cqrs,我目前正在研究使用NServiceBus来解决以下问题。我只是想确保我不会带着这个掉进兔子洞 我有一个基于CQRS体系结构的解决方案。本质上,我有一系列命令通过NServiceBus传递到端点,我执行一些处理来改变聚合根的状态,然后触发一系列事件来通知系统的其余部分这些更改 我的问题是,这一切在一个线程上都非常有效,在这个线程中,我不需要担心在更改状态时锁定任何给定的聚合根 我们已经到了一个线程无法处理消息的地步,我需要开始研究使用多个工作线程/进程来处理消息 由于我可以同时处理多个聚合根,因此

我目前正在研究使用NServiceBus来解决以下问题。我只是想确保我不会带着这个掉进兔子洞

我有一个基于CQRS体系结构的解决方案。本质上,我有一系列命令通过NServiceBus传递到端点,我执行一些处理来改变聚合根的状态,然后触发一系列事件来通知系统的其余部分这些更改

我的问题是,这一切在一个线程上都非常有效,在这个线程中,我不需要担心在更改状态时锁定任何给定的聚合根

我们已经到了一个线程无法处理消息的地步,我需要开始研究使用多个工作线程/进程来处理消息

由于我可以同时处理多个聚合根,因此存在一个自然的任务故障,但是我不能同时为同一聚合根处理多个消息,因为这将由于接收消息的速度而导致高争用

我试图避免这样的情况:我需要锁定一个特定的聚合根id,而将聚合根分配给队列/线程/进程,这将确保同步处理来自同一聚合根的所有消息

我正在使用带有NServiceBus的发布/订阅模型发布事件。在我看来,问题在于这些事件需要从同一个端点发布,即使该消息的处理可能委托给另一个端点。i、 e.我需要诱使系统认为消息是从“MyDomainQueue”发布的,而实际上消息是在“MyDomainQueue-Worker1”上处理的

我的计划是创建一个自定义分发服务器,它将允许主端点将消息处理委托给工作端点。分发服务器将以循环方式将队列分配给任何给定的聚合根。主端点将向这些工作者发送命令,进行处理,工作者将用事件列表进行回复。然后,主端点将事件发布回总线

我正在寻找有关这种方法的一些反馈。我觉得我正在努力工作,以使这项工作,我只是想看看是否有其他人已经处理了类似的问题。也许NServiceBus是这项工作的错误工具,或者我的方法是错误的。欢迎任何反馈

谢谢


PS-我还担心上述解决方案所需的配置量。

关于从不同端点发布事件,我认为您对从一个服务发布事件的概念有点太过关注了。这仅在逻辑意义上是正确的-一个事件应该完全由一个逻辑服务拥有,但是一个逻辑服务可以由多个端点组成

事件实际上不是从队列发布的。当您想到发布事件的队列时,您真正谈论的是输入队列,您可以在其中发送该事件的订阅请求

因此,您可以让多个端点都发布同一事件,只要该事件的订阅请求都位于同一位置

这通常是一种情况,例如,在批量与优先级方案中,您有两个端点处理相同的命令(然后发布相同的事件),除了一个是具有长SLA的批量,而另一个具有更短的SLA-可能是一个大客户,或者该命令来自等待响应的实际用户。QueueA和PriorityQueueA都处理相同的命令并发布相同的事件,但QueueA处理订阅,因此都处理“从”QueueA发布

也就是说,您是否尝试过让多个线程访问聚合根?即使存在一些争议,您也可能会发现,通过少量重试,可能不会像您想象的那样引起争议。在使用NServiceBus的生产过程中,我有一些相当有争议的过程,尽管我在日志中偶尔会看到争用的迹象,但在5次重试后,我从未将这些进展记录到错误队列中

--最近,添加了第二级重试功能,这进一步降低了消息进入错误队列的可能性


如果存在如此多的争用,另一种策略可能是在内存中维护当前正在操作的聚合根的列表,然后如果传入一条应该被“锁定”的消息,只需调用
Bus.HandleCurrentMessageLater()
将该消息粘贴回队列末尾。

您看过内置分发服务器吗?在下面的3/4页中,我们可以看到它描述了一个按比例缩小的发布/订阅模型。谢谢你的建议。我将进入poc,提供进度反馈。Bus.HandleCurrentMessageLater()让我开始思考。我应该能够解决这个问题。只是一个关于拥有多个端点的逻辑服务的问题。这是否意味着订阅者将需要在两个(所有)端点上订阅相同的事件?否,订阅者从一个逻辑权威源订阅(或者更确切地说,向一个逻辑权威源发送订阅请求)。这就是订阅存储发生的地方。然后,多个物理端点可以作为一个统一的逻辑发布服务器发布同一事件。我使用HandleCurrentMessageLater实现了一个“锁定”机制,并保留了一个当前正在处理的聚合根列表,该列表运行良好。不过,稍后使用HandleCurrentMessage时,请注意一点。如果它不被检查,你可能会出现一些丑陋的无限循环行为。