【问题标题】:In RabbitMQ, how to handle the conflict between prefetch and 'redelivered'在 RabbitMQ 中,如何处理 prefetch 和 'redelivered' 之间的冲突
【发布时间】:2018-05-22 06:59:53
【问题描述】:

基本上我也有类似的问题:

http://rabbitmq.1065348.n5.nabble.com/Consumer-crash-redelivery-and-prefetch-td34103.html

我想预取一些消息以提高性能。 同时,如果一条消息失败,我确实想再给它一次机会(重试两次),目前我使用“redelivered”标志来实现这一点。如果没有设置'redelivered',我会重新排队消息,否则我会放弃消息。 如果消费者由于尚未处理而崩溃但会设置“重新传递”标志,这将导致那些预取消息(尚未处理)出现问题。

有什么解决办法吗?或者任何其他更好的方法来实现 RabbitMQ 消息的重试逻辑? 谢谢,

【问题讨论】:

    标签: rabbitmq prefetch


    【解决方案1】:

    我发现这种逻辑存在一些问题,您已经发现了其中一个问题。首先,redelivered 标志是一个非常无用的字段——它为无状态操作提供状态指示(处理消息不应要求提供任何“外部”信息)。通常,您的消息处理器不应该关心消息是否已被传递 1、10 或 100 次 - 消息的处理和相关行为不应取决于它被传递的次数。

    另一个更微妙的问题是,您有几种不同的故障模式,具有不同的影响,您发现将所有这些都减少到单个 redelivered 布尔值并不是一个好主意。

    你可以做几件事:

    首先,您应该尝试区分由错误消息引起的故障与由服务器临时状况引起的故障。前者将永远无法被处理(并且应该被彻底拒绝),而后者可能会在条件解决后被处理。现在,你如何在两者之间做出选择?您如何决定在重试之前等待多长时间?

    其次,如果您确实需要了解之前的故障,您可以在消息中添加标头并重新发布(而不是使用basic.reject)。消息将排到队列的后面,但此状态信息现在将成为消息的一部分并可供未来的处理器使用。

    如果这是一个请求-回复方案,那么只需拒绝该消息并让客户端重试请求。如果客户端无法知道消息何时/是否被处理,显然这是不可取的。

    【讨论】:

    • 感谢您的回复。我喜欢“添加标题”和“重新发布”的方式。另外我发现我不能直接在消费者回调函数中修改标题,然后再使用重新入队(这样我就不需要“重新发布”)?似乎是只读给消费者的。
    • 另外,关于不同的失败,对,如果是消息格式错误,我会丢弃该消息。否则我想在这里实现一些重试逻辑。我需要一个占位符来记录这条消息已经重试了多少次。理想情况下,占位符应该在消息中(不是我的程序)
    • 你说得对,重新发布与“nack”不同——在“nack”场景下不能以任何方式修改消息。如果次数很重要,我同意将其与消息一起存储是最有意义的。
    【解决方案2】:

    您是否考虑过使用dead letter exchange

    基本上,您不会将失败的消息重新排队,而是拒绝它。 如果您配置了死信交换,您可以为该被拒绝的消息设置一个新流程,例如将其放在您的进程也订阅的另一个队列中。

    有了这样的机制,所有的消息都会被处理至少两次,这似乎是你的目标。

    【讨论】:

      猜你喜欢
      • 2013-08-15
      • 1970-01-01
      • 2020-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-13
      相关资源
      最近更新 更多