【原创】RabbitMQ之PublisherConfirm实战问题总结


如何理解Publisher Confirm机制

      Publisher Confirm机制(又称为ConfirmsPublisher Acknowledgements)是作为解决事务机制性能开销大(导致吞吐量下降)而提出的另外一种保证消息不会丢失的方式。

Publisher Confirm的协议交互过程



(补充说明:上图中未显示出info信息的两条交互对应的就是 Confirm.Select 和 Confirm.Select-ok ,显示不出来是因为 wireshark 没有对该扩展进行支持


(手绘图一张,字迹潦草了些)


      为了使能
Confirm机制,client 首先要发送 confirm.select 方法帧。取决于是否设置了 no-wait属性broker 会相应的判定是否以 confirm.select-ok 进行应答。一旦在 channel 上使用 confirm.select 方法,channel 就将处于 confirm 模式。处于 transactional 模式 channel 不能再被设置成 confirm 模式,反之亦然。

      一旦 channel 处于 confirm 模式,broker client (注:client 侧计数需要自行实现)都将启动消息计数(以 confirm.select 为基础从 1 开始计数)。broker 会在处理完消息后,在当前 channel 上通过发送 basic.ack 的方式对其进行 confirm delivery-tag 的值标识了被 confirm 消息的序列号。broker 也可以通过设置 basic.ack 中的 multiple 来表明到指定序列号为止的所有消息都已被 broker 正确的处理了。

      在发生异常情况发生时,broker 将无法成功处理相应的消息,此时 broker 将发送 basic.nack 来代替 basic.ack 。在这个情形下,basic.nack 中各域值的含义与 basic.ack 中相应各域含义是相同的,同时 requeue 域的值应该被忽略。通过 nack 一条或多条消息,broker 表明自身无法对相应消息完成处理,并拒绝为这些消息的处理负责。在这种情况下,client 可以选择将消息 re-publish

      channel 被设置成 confirm 模式之后,所有被 publish 的消息都将被 confirm(即 ack) 或者被 nack 一次。但是没有针对消息被 confirm 的快慢做任何保证,但是限制了同一条消息不会既被 confirm 又被 nack

目前情况下,basic.nack 信令只会在负责 queue 功能的 Erlang 进程发生内部错误时被发送


消息在何时被 Confirm

      这个部分是该机制的核心,也是最容易被理解错误的地方。首先看下一下我之前翻译过的官网针对该问题的说明。可以针对该问题,官网的说法有了一些微妙的调整。

如果将上述说明拆开后进行对应,则为下面的部分:

对应了

(关于mandatory属性的说明,可以参考《RabbitMQ 之 mandatory》)

对应了

两者对比后,可以看到

这条约束被移除了!!其背后真正的原因可以参考《RabbitMQ publish方法中的immediate和mandatory属性》里针对immediate属性的详细解释。

简要的讲,就是

Support for "immediate" made many parts of the codebase more complex, particularly around mirrored queues. It also stood in the way of our being able to deliver substantial performance improvements in mirrored queues.

好了,到此总结一下上面内容中比较隐晦的点:

第一,mandatory属性的使用和Publisher Confirm机制没有必然关系(其实immediate属性也是这样,但因为该属性后续不被支持了,所以此处不进行讨论了)。

上图展示的就是,单独使用mandatory属性测试exchange绑定了queue和未绑定queue时的两种情况。

第二,只有将mandatory属性和Publisher Confirm机制结合使用,才能真正实现消息的可靠投递(消息到queue中)

      上面给出的是调用Basic.Publish方法时可以设置的属性。下面这张图展示的是启用了Publisher Confirm机制但是没有设置mandatory属性的情况,同时所投递的目标exchange也没有进行queue绑定。

而下面这个是绑定了queue的情况。

      可以看到,两种情况下,服务器的回应是没有差别的,都是对消息应答Basic.Ack。而事实上,第一种情况下,消息已经被blackholed了。很诡异吧,消息丢失了,却仍旧可以收到来自服务器的Ack。这也是实际使用中容易犯的错误。

再次将官方说明写在这里:

“对于无法路由的消息,broker 会在确认了通过 exchange 无法将消息路由到任何 queue 后,发送回客户端 basic.ack 进行确认(其中包含空的 queue 列表)。如果客户端发送消息时使用了 mandatory 属性,则会发送回客户端 basic.return + basic.ack 信息。”

貌似其中说,发回的basic.ack中会包含一个空的queue列表。但是确实没看到。既然如此还是乖乖的使用mandatory属性吧,使用后效果如下

      可以看到消息被通过Basic.Return发送回来,且告知原因是NO_ROUTE。同时通过Basic.Ack告知当前消息的Delivery-Tag1。于是乎,客户端侧可以根据回应进行相应的处理了(比如重新publish等)。

第三,在immediate属性被移除后,若想通过Publisher Confirm机制实现类似immediate对应的功能(即消息立即被Consumer消费,若未被消费,则Producer要知道),则需要结合DLXTTL设置。

一种可能的方案是:

  • 为目标queue设置DLX;
  • 为DLX绑定回收消息的queue,并对其进行consume;
  • 在通过 basic.publish 发送消息时针对每一条消息设置 expiration 字段为0;

关于DLXTTL的说明可以参考:

RabbitMQ 之 Dead Letter Exchanges(翻译)》和《RabbitMQ 之 TTL 详解(翻译) 

总结

本文针对RabbitMQ中的Publisher Confirm机制展开讨论,针对常见属性进行说明,并对可能遇到的问题给出方案建议。



转载于:https://my.oschina.net/moooofly/blog/393753

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值