【问题标题】:Mix Commands with Events in message broker(ServiceBus)在消息代理(ServiceBus)中混合命令和事件
【发布时间】:2021-11-08 13:38:19
【问题描述】:

我有 OrderOrderProcessor 服务。 订单提交后,必须由 OrderProcessor 处理。处理后,OrderProcessor 应该将响应发送到 Order 服务,并带有 Order 状态,例如失败/成功。我想使用消息代理(Azure ServiceBus)进行异步处理和解耦我的服务。

在命令和事件方面,我看到以下结构:

  • ProcessOrder 命令应该在 ServiceBus 中发布。我选择了命令消息,因为我希望处理器进行一些处理。而且只有一个消费者。
  • OrderProcessedFailedOrderProcessedSucceeded 事件应在处理完成后在 ServiceBus 中发布。所以我的 Order 服务应该订阅这些事件并正确处理。

在 ServiceBus 中使用队列或主题有两种方法可以实现它。 我想使用一个共享主题,其中将发布 ProcessOrder 消息和 OrderProcessedFailed/OrderProcessedSucceeded 事件。每个服务都有自己的订阅,按事件类型过滤。

我知道,当您采用事件驱动方法时,共享主题结构是简单场景的不错选择。但就我而言,我也有 ProcessOrder 命令。我期待订单将被处理。当我只是提出 OrderCreated 事件(或其他任何事件)并期望对此有任何反应时,情况就不一样了。

在一个共享主题中混合命令和事件实际上是一种好方法,还是完全混合命令和事件? 将消息驱动的方法与请求和回复队列一起使用会更好吗?并将响应事件替换为 OrderReply 消息(内部带有 Failed/Succeeded 状态)?

其他信息:

我不确定将来会是任何其他命令或/和事件。但如果是这样,最好有易于维护的结构,例如所有服务的共享主题。

我现在知道应该支持不同版本的 OrderProcessors。而且我相信使用带有过滤器的主题和订阅者来处理命令消息版本会更容易。而不仅仅是在应用程序级别过滤消息。

【问题讨论】:

    标签: azureservicebus azure-servicebus-queues messagebroker azure-servicebus-topics event-driven


    【解决方案1】:

    对此不一定有硬性规定,但我个人会采用一种用于命令和一种用于事件的方法——也就是主题和目的之间的 1-1 映射。如果您需要在构建服务时扩展该主题,那么使用具有单个订阅者的主题没有任何问题。

    添加不同的 OrderProcessor 可能会很好地使用过滤器,无论是在服务中还是在您的代码中。他们每个人都可以对命令主题有自己的订阅,这样订单服务就不需要知道给定命令最终将使用哪个处理器。

    接下来要考虑的是向混合中添加一种完全不同类型的服务——比如从 OrderProcessor 接收命令的东西。如果您最终预计服务的数量会随着复杂的连接而变得相当大,那么拥有该中心命令主题可能是一个不错的选择 - 它允许来自任何组件的命令移动到任何其他组件。

    另一方面,如果您的服务类型仍然偏低,那么更狭义地定义目的可能是有意义的——比如将 orderCommands 和 inventoryCommands 分开。如果这是您喜欢的设计,那么在那种情况下使用单个命令主题也不会错。

    您还可以使用自动转发将两者结合起来。您的中心命令主题接收所有消息,然后将它们自动转发到 orderCommands 和 inventoryCommands 主题。在大型系统中,这会使您为单个主题管理的订阅数量有所减少。

    【讨论】:

    • 我终于想出了下面的结构。命令的一个共享主题,用于支持不同版本的 OrderProcessors 以及可能来自其他服务的不同命令。事件的一个共享主题,因此所有服务都将使用它和每个订阅的过滤器。如果需要,一个共享队列/主题用于回复消息/命令。如果来自服务的命令/请求需要来自其他服务的回复。对我来说,将命令、事件和回复分开是很有意义的。现在更简单,然后每个命令有一个队列/主题等。根据您的 1-1 映射建议看起来不错。
    • 有道理——它本质上是一种平衡行为——它更多的是能够管理系统而不是任何事情。太多的主题/队列或太多的主题订阅可能会很笨拙。有目的的 1:1 映射还可以更容易地推断流量是如何流动的,并在主题之间创建自然划分..
    • 同意,现在很清楚了。顺便说一句,您如何看待将命令与事件混合在一起?例如这里建议使用消息或事件驱动架构docs.microsoft.com/en-us/dotnet/architecture/microservices/…。我还阅读了一些不推荐将事件与命令/消息混合的文章。
    • 我认为这两种方法都有很好的论据——如果你有一个好的路由系统,那么单个主题可能会非常有效,因为所有出站消息都会发送到一个位置。我相信我对拆分它们的偏好正是——一种偏好。如果目标是让发送者不需要了解接收者,那么任何一种方法都可以工作。通过拆分它们,发送者需要决定发送到哪个主题,但它仍然不关心另一端的谁来接收它们。