【问题标题】:How to guarantee delivery of messages in MassTransit?MassTransit 如何保证信息的传递?
【发布时间】:2021-10-02 11:42:04
【问题描述】:

我试图弄清楚如何使用 MassTransit 实施容错消息发布解决方案。我们将关注一个简​​单的场景,我们只需要提交一个数据库更改,并发布一个指示该更改的事件。因为没有(内置)机制允许原子“提交和发布”,我们的进程崩溃时,我们进入不一致的状态(一些消息会只提交到数据库,有些可能只发布到消息队列)。

This documentation page 提供了一个解决方案,因为我们假设消息处理是幂等的,所以我们可以依靠在失败的情况下重试整个操作,并且这些部分提交将得到解决最终。这是一个很好的解决方案,但它只有一个警告:它假设我们正在执行的操作是由消息触发的,如果我们不发送 ack,将重试处理。这不是一个合理的假设,因为消息传递通常仅用于系统内部的内部通信,而不用于与外部世界的通信。处理来自外部客户端的 HTTP 请求时,需要保存和发布时应该怎么做?

一种可能的解决方案是破解文章中介绍的方法,只发布(或发送)一条消息,并自己收听它,然后在消息处理程序中我们执行提交并发布实际的我们希望其他人听到的事件。我遇到的主要问题是它假设我们永远不必在 HTTP 响应中返回任何内容。如果我们需要向 HTTP 客户端指示数据库事务的成功或失败怎么办? (例如:如果我们依赖 UNIQUE 约束来告诉我们是否应该接受请求,并且我们想向客户端指示失败)。我们可以通过在消息队列上使用请求-响应(与我们自己)来解决它,但这很丑陋,并且会大大增加延迟和复杂性,这实际上是一种非常常见的场景。

我在互联网上看到最多的解决这个问题的方法是使用一个持久化到我们需要写入的同一个数据库的发件箱,因此我们可以将这两个操作包装在一个常规的 ACID 数据库事务中.然后后台任务轮询该数据库以查找新事件并将它们发布到消息代理。与其他框架不同,我知道 MassTransit 不支持这种开箱即用的行为。所以我想我的问题可以归结为:在自己急于实现这个相对复杂的机制之前(每个数据库技术一次),我还缺少另一个解决方案吗? MassTransit 社区对此问题的公认解决方案是什么?

【问题讨论】:

  • 我没有想到其他解决方案。我们确实有一个额外的消息存储和额外的任务,应该从它可靠地发布。这解决了一个问题,但将可能的不一致推向了管道。请注意,它不仅仅与 MassTransit 相关。
  • @WiktorZychla 你是如何实现后台轮询的?您是否假设只有一个消息发布者实例?因为如果不是这样,这将成为一项非常棘手的任务(不会让消息代理充满重复)。
  • 是的,只有一个。需要时,它会水平扩展,只有另一个 storage-publisher 副本,应用程序使用循环法来选择要保存到的存储空间。

标签: c# publish-subscribe messaging masstransit


【解决方案1】:

这里和其他地方已经以各种形式多次询问过这个问题。但简短的回答很简单。

在您的控制器中,仅写入消息代理。让消费者在使用可靠消息的上下文中处理数据库,并使用该上下文中可用的所有不错的重试和重新传递选项。然后,您将获得 InMemoryOutbox 的所有好处,而不会增加与在单个对话中拥有第三方(HTTP、数据库和代理)相关的极端复杂性。

【讨论】:

  • 您是否还建议仅在消费者中处理数据库查询?因为这似乎有点慢,而不是只做一劳永逸的工作
  • 查询没有副作用,或者不应该,所以不,我不会使用消息来查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多