当前位置: 首页 > news >正文

【原创】RabbitMQ 之 no_ack 分析

2019独角兽企业重金招聘Python工程师标准>>> hot3.png


      熟悉 RabbitMQ 的人肯定知道  no_ack 属性是在调用 Basic.Consume 方法时可以设置的一个重要参数。本文主要针对 no_ack 设置的两种情况,通过抓包分析的形式讲解下实际应用中的异同,并总结一下相关的处理经验。

============ 我是分隔线 =============

      no_ack 的用途:确保 message 被 consumer “成功”处理了。这里“成功”的意思是,(在设置了 no_ack=false 的情况下)只要 consumer 手动应答了 Basic.Ack ,就算其“成功”处理了。

情况一no_ack=true (此时为自动应答
      在这种情况下,consumer 会在接收到 Basic.Deliver + Content-Header + Content-Body 之后,立即回复 Ack 。而这个 Ack 是 TCP 协议中的 Ack 。此 Ack 的回复不关心 consumer 是否对接收到的数据进行了处理,当然也不关心处理数据所需要的耗时。

图1:(Producer+Consumer)


图2:(Consumer)


图3:(Producer)


情况二:no_ack=false (此时为手动应答
      在这种情况下,要求 consumer 在处理完接收到的 Basic.Deliver + Content-Header + Content-Body 之后才回复 Ack 。而这个 Ack 是 AMQP 协议中的 Basic.Ack 。此 Ack 的回复是和业务处理相关的,所以具体的回复时间应该要取决于业务处理的耗时。

图4:(Producer+Consumer)


图5:(Consumer)


图6:(Producer)


总结:

  • Basic.Ack 发回给 RabbitMQ 以告知,可以将相应 message 从 RabbitMQ 的消息缓存中移除。
  • Basic.Ack 未被 consumer 发回给 RabbitMQ 前出现了异常,RabbitMQ 发现与该 consumer 对应的连接被断开,之后将该 message 以轮询方式发送给其他 consumer (假设存在多个 consumer 订阅同一个 queue)。
  • 在 no_ack=true 的情况下,RabbitMQ 认为 message 一旦被 deliver 出去了,就已被确认了,所以会立即将缓存中的 message 删除。所以在 consumer 异常时会导致消息丢失。
  • 来自 consumer 侧的 Basic.Ack 与 发送给 Producer 侧的 Basic.Ack 没有直接关系。

 


============ 我是分隔线 =============

最后贴上自己改造的、基于 libevent 实现的 rabbitmq-c 的测试打印。

情况一:

[warn] evsignal_init: socketpair: No error
drive_machine: [conn_init]  ---  in TCP 3-way connecting!
drive_machine: [conn_connecting]  ---  connection timeout 1 time on socket(6040)
drive_machine: [conn_connected]  ---  connected on socket(6040)

6040: conn_state change   connected ==> snd_protocol_header
  --> Send Protocol.Header!
6040: conn_state change   snd_protocol_header ==> rcv_connection_start_method
  <-- Recv Connection.Start Method frame!
6040: conn_state change   rcv_connection_start_method ==> snd_connection_start_rsp_method
  --> Send Connection.Start-Ok Method frame!
6040: conn_state change   snd_connection_start_rsp_method ==> rcv_connection_tune_method
  <-- Recv Connection.Tune Method frame!
6040: conn_state change   rcv_connection_tune_method ==> snd_connection_tune_rsp_method
  --> Send Connection.Tune-Ok Method frame!
6040: conn_state change   snd_connection_tune_rsp_method ==> snd_connection_open_method
  --> Send Connection.Open Method frame!
6040: conn_state change   snd_connection_open_method ==> rcv_connection_open_rsp_method
  <-- Recv Connection.Open-Ok Method frame!
6040: conn_state change   rcv_connection_open_rsp_method ==> snd_channel_open_method
  --> Send Channel.Open Method frame!
6040: conn_state change   snd_channel_open_method ==> rcv_channel_open_rsp_method
  <-- Recv Channel.Open-Ok Method frame!
6040: conn_state change   rcv_channel_open_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Queue Declaring!
6040: conn_state change   idle ==> snd_queue_declare_method
  --> Send Queue.Declare Method frame!
6040: conn_state change   snd_queue_declare_method ==> rcv_queue_declare_rsp_method
  <-- Recv Queue.Declare-Ok Method frame!
6040: conn_state change   rcv_queue_declare_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Queue Binding!
6040: conn_state change   idle ==> snd_queue_bind_method
  --> Send Queue.Bind Method frame!
6040: conn_state change   snd_queue_bind_method ==> rcv_queue_bind_rsp_method
  <-- Recv Queue.Bind-Ok Method frame!
6040: conn_state change   rcv_queue_bind_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Basic QoS!
6040: conn_state change   idle ==> snd_basic_qos_method
  --> Send Basic.Qos Method frame!
6040: conn_state change   snd_basic_qos_method ==> rcv_basic_qos_rsp_method
  <-- Recv Basic.Qos-Ok Method frame!
6040: conn_state change   rcv_basic_qos_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Basic Consuming!
6040: conn_state change   idle ==> snd_basic_consume_method
  --> Send Basic.Consume Method frame!
6040: conn_state change   snd_basic_consume_method ==> rcv_basic_consume_rsp_method
  <-- Recv Basic.Consume-Ok Method frame!
6040: conn_state change   rcv_basic_consume_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Start waiting to recv!
6040: conn_state change   idle ==> rcv_basic_deliver_method
drive_machine: wait for Basic.Deliver method another 10 seconds!!
drive_machine: wait for Basic.Deliver method another 10 seconds!!

  <-- Recv Basic.Deliver Method frame!
6040: conn_state change   rcv_basic_deliver_method ==> rcv_basic_content_header
  <-- Recv Content.Header frame!
6040: conn_state change   rcv_basic_content_header ==> rcv_basic_content_body
  <-- Recv Content.Body frame!
Content Body is [Hello World betty].
@@@ CB: body len : [17]    body : [Hello World betty]
6040: conn_state change   rcv_basic_content_body ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Start waiting to recv!
6040: conn_state change   idle ==> rcv_basic_deliver_method
drive_machine: wait for Basic.Deliver method another 10 seconds!!
drive_machine: wait for Basic.Deliver method another 10 seconds!!


情况二:

[warn] evsignal_init: socketpair: No error
drive_machine: [conn_init]  ---  in TCP 3-way connecting!
drive_machine: [conn_connecting]  ---  connection timeout 1 time on socket(6040)
drive_machine: connected on socket(6040)
6040: conn_state change   connected ==> snd_protocol_header
  --> Send Protocol.Header!
6040: conn_state change   snd_protocol_header ==> rcv_connection_start_method
  <-- Recv Connection.Start Method frame!
6040: conn_state change   rcv_connection_start_method ==> snd_connection_start_rsp_method
  --> Send Connection.Start-Ok Method frame!
6040: conn_state change   snd_connection_start_rsp_method ==> rcv_connection_tune_method
  <-- Recv Connection.Tune Method frame!
6040: conn_state change   rcv_connection_tune_method ==> snd_connection_tune_rsp_method
  --> Send Connection.Tune-Ok Method frame!
6040: conn_state change   snd_connection_tune_rsp_method ==> snd_connection_open_method
  --> Send Connection.Open Method frame!
6040: conn_state change   snd_connection_open_method ==> rcv_connection_open_rsp_method
  <-- Recv Connection.Open-Ok Method frame!
6040: conn_state change   rcv_connection_open_rsp_method ==> snd_channel_open_method
  --> Send Channel.Open Method frame!
6040: conn_state change   snd_channel_open_method ==> rcv_channel_open_rsp_method
  <-- Recv Channel.Open-Ok Method frame!
6040: conn_state change   rcv_channel_open_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Queue Declaring!
6040: conn_state change   idle ==> snd_queue_declare_method
  --> Send Queue.Declare Method frame!
6040: conn_state change   snd_queue_declare_method ==> rcv_queue_declare_rsp_method
  <-- Recv Queue.Declare-Ok Method frame!
6040: conn_state change   rcv_queue_declare_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Queue Binding!
6040: conn_state change   idle ==> snd_queue_bind_method
  --> Send Queue.Bind Method frame!
6040: conn_state change   snd_queue_bind_method ==> rcv_queue_bind_rsp_method
  <-- Recv Queue.Bind-Ok Method frame!
6040: conn_state change   rcv_queue_bind_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Basic QoS!
6040: conn_state change   idle ==> snd_basic_qos_method
  --> Send Basic.Qos Method frame!
6040: conn_state change   snd_basic_qos_method ==> rcv_basic_qos_rsp_method
  <-- Recv Basic.Qos-Ok Method frame!
6040: conn_state change   rcv_basic_qos_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Basic Consuming!
6040: conn_state change   idle ==> snd_basic_consume_method
  --> Send Basic.Consume Method frame!
6040: conn_state change   snd_basic_consume_method ==> rcv_basic_consume_rsp_method
  <-- Recv Basic.Consume-Ok Method frame!
6040: conn_state change   rcv_basic_consume_rsp_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Start waiting to recv!
6040: conn_state change   idle ==> rcv_basic_deliver_method
drive_machine: wait for Basic.Deliver method another 10 seconds!!
drive_machine: wait for Basic.Deliver method another 10 seconds!!
drive_machine: wait for Basic.Deliver method another 10 seconds!!

  <-- Recv Basic.Deliver Method frame!
6040: conn_state change   rcv_basic_deliver_method ==> rcv_basic_content_header
  <-- Recv Content.Header frame!
6040: conn_state change   rcv_basic_content_header ==> rcv_basic_content_body
  <-- Recv Content.Body frame!
Content Body is [Hello World betty].
@@@ CB: body len : [17]    body : [Hello World betty]
6040: conn_state change   rcv_basic_content_body ==> snd_basic_ack_method
  --> Send Basic.Ack Method frame!
6040: conn_state change   snd_basic_ack_method ==> idle

drive_machine: [conn_idle]  ---  [CONSUMER]: Start waiting to recv!
6040: conn_state change   idle ==> rcv_basic_deliver_method
drive_machine: wait for Basic.Deliver method another 10 seconds!!
drive_machine: wait for Basic.Deliver method another 10 seconds!!





 

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

相关文章:

  • 解析XML文档大致流程以及相关方法
  • Tomcat日志分析
  • h5渲染性能一瞥
  • IIS7多域名绑定同一物理目录,设置不同默认文档的最佳解决方案
  • Hadoop分布式配置文件
  • Git 解决本地远端版本冲突
  • 使用Setup安装Windows8 RTM方法
  • Codeforces 101572 D - Distinctive Character
  • 中央政府释放重大利好 2015年信息消费将超3万亿
  • 在vue中使用SockJS实现webSocket通信
  • 虚度的日子们
  • Service 保活法之一
  • 新手学习SQL 注入式***
  • ajax取到数据后如何拿到data.data中的属性值
  • python中的魔术属性与魔法方法
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • .pyc 想到的一些问题
  • [译]Python中的类属性与实例属性的区别
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • 07.Android之多媒体问题
  • codis proxy处理流程
  • docker-consul
  • Javascripit类型转换比较那点事儿,双等号(==)
  • Java超时控制的实现
  • Js基础——数据类型之Null和Undefined
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • Median of Two Sorted Arrays
  • October CMS - 快速入门 9 Images And Galleries
  • python 学习笔记 - Queue Pipes,进程间通讯
  • tensorflow学习笔记3——MNIST应用篇
  • 从零搭建Koa2 Server
  • 搭建gitbook 和 访问权限认证
  • 搞机器学习要哪些技能
  • 记录一下第一次使用npm
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 项目管理碎碎念系列之一:干系人管理
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • FaaS 的简单实践
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​ubuntu下安装kvm虚拟机
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • !!java web学习笔记(一到五)
  • #14vue3生成表单并跳转到外部地址的方式
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • (13)Hive调优——动态分区导致的小文件问题
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (免费分享)基于springboot,vue疗养中心管理系统