消费者确认解决的问题是确认消息是否被消费者"成功消费".

它有个前提条件,那就是生产者发布的消息已经"成功"发送出去了.

因此还需要一个机制来告诉生产者,你发送的消息真的"成功"发送了.

在标准的AMQP 0-9-1,保证消息不会丢失的唯一方法是使用事务:在通道上开启事务,发布消息,提交事务.但是事务是非常重量级的,它使得RabbitMQ的吞吐量降低250倍.为了解决这个问题,RabbitMQ 引入了 发布者确认(Publisher Confirms) 机制,它是模仿AMQP协议中的消费者消息确认机制.

事务机制

生产者部分代码:

         try
{
channel.TxSelect();//开启事务机制
channel.BasicPublish("", QueueName, null, Encoding.Default.GetBytes("hello world"));
channel.TxCommit();//提交
Console.WriteLine($"send {msg}");
}
catch (Exception e)
{
channel.TxRollback();//回滚
Console.WriteLine(e);
}

发布者确认

一旦在信道上使用 confirm.select 方法,就认为该信道处于Publisher Confirms模式.事务信道不能进入Publisher Confirms模式,一旦信道处于Publisher Confirms模式,不能开启事务.即事务和Publisher Confirms模式只能二选一.

发布的消息什么时候会被broker确认?

对于不可路由的消息,broker 将在 exchange 验证消息不会路由到任何队列(发回一个空的队列列表)后发出确认;如果消息被设置为"必需消息"发布,即 BasicPublish() 方法的 "mandatory" 入参为true,那么 BasicReturn 事件将在 BasicAcks 事件之前触发.否定确认 BasicNacks 事件也是如此.

对于可路由消息,当所有队列都接受消息时才触发 BasicAcks 事件,对于路由到持久话队列的持久性消息,这意味着持久化到磁盘后才会触发 BasicAcks 事件;对于消息的镜像队列,这意味着所有镜像都已接受该消息后才会触发 BasicAcks 事件.

发布者确认分为同步和异步两种.

一.同步

生产者部分代码

            //开启confirm机制
channel.ConfirmSelect();
string msg = "hello world ";
for (int i = ; i < ; i++)
{
channel.BasicPublish("", QueueName, null, Encoding.Default.GetBytes(msg + i));
}        //可以发送一批消息后,调用该方法;也可以每发一条调用一次.      
if (channel.WaitForConfirms())
{
Console.WriteLine("send is success");
}
else
{
Console.WriteLine("send is failed");
         //实际应用中,这里需要添加发送消息失败的处理逻辑.
         //如果是发送一批消息,那么只要有一条失败,则所有的消息发送都会失败.
}

二.异步

生产者部分代码

          channel.ConfirmSelect();  

                //肯定确认
channel.BasicAcks += (s, e) =>
{
//多条
if (e.Multiple)
{
Console.WriteLine("最后成功的一条是 : " + e.DeliveryTag);
}
//单条
else
{
Console.WriteLine(e.DeliveryTag + " 成功发送 ");
}
}; //否定确认
channel.BasicNacks += (s, e) =>
{
//多条
if (e.Multiple)
{
Console.WriteLine("最后失败的一条是 : " + e.DeliveryTag);
}
//单条
else
{
Console.WriteLine(e.DeliveryTag + " 发送失败 ");
}
};

发布者的否定确认(BasicNacks)

  • 在特殊情况下,当 broker 无法成功处理消息而不是 BasicAck 时,broker 将发送 BasicNack.在这种情况下,BasicNack 的字段与 BasicAck 相对应的字段意义相同,并且 requeue 字段是没有意义的.是否重发消息由发送者自己决定;
  • 将channel设置为发布者确认模式后,所有后续发布的消息都只会被 confirm 一次或者 nack 一次;
  • 没有机制保证消息需要多久被 confirmed;
  • 消息不会同时被confirmed和nack`d;
  • BasicNacks 事件只在负责队列的Erlang进程中发生内部错误时才会触发;

持久化消息的延迟肯定确认

前面说到,

如果是持久化的消息,要等到消息持久化到磁盘后才会触发 BasicAcks 事件;对于消息的镜像队列,要等到所有镜像都已接受该消息后才会触发 BasicAcks 事件.

而为了保证持久化效率, RabbitMQ不是来一条存一条,而是定时批量地持久化消息到磁盘.RabbitMQ 消息存储一段时间(几百毫秒)之后或者当队列空闲时,才会批量写到磁盘.

这意味着在恒定负载下,BasicAck 的延迟可以达到几百毫秒.如果队列支持镜像队列,则延迟时间更大.

所以,为了提高吞吐量,强烈建议应用程序采用异步确认方式,或者发布批量消息后等待确认.

发布者确认的注意事项

在大多数情况下,RabbitMQ将以与发布时相同的顺序向发布者确认消息(这适用于在单个频道上发布的消息).但是,发布者确认是异步发出的,可以确认单个消息或一组消息.发出确认的确切时刻取决于消息的传递模式(持久性与瞬态)以及消息路由到的队列的属性.也就是说,RabbitMQ可能不以消息发布的顺序向发布者发送确认消息.生产者端尽量不要依赖消息确认的顺序处理业务逻辑.

RabbitMQ (十二) 消息确认机制 - 发布者确认的更多相关文章

  1. RabbitMQ (十一) 消息确认机制 - 消费者确认

    由于生产者和消费者不直接通信,生产者只负责把消息发送到队列,消费者只负责从队列获取消息(不管是push还是pull). 消息被"消费"后,是需要从队列中删除的.那怎么确认消息被&q ...

  2. RabbitMQ (十六) 消息队列的应用场景 (转)

    原贴 : http://blog.csdn.net/cws1214/article/details/52922267 消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题 ...

  3. RabbitMQ消息发布和消费的确认机制

    前言 新公司项目使用的消息队列是RabbitMQ,之前其实没有在实际项目上用过RabbitMQ,所以对它的了解都谈不上入门.趁着周末休息的时间也猛补习了一波,写了两个窗体应用,一个消息发布端和消息消费 ...

  4. Rabbitmq可靠消息投递,消息确认机制

    前言 我们知道,消息从发送到签收的整个过程是 Producer-->Broker/Exchange-->Broker/Queue-->Consumer,因此如果只是要保证消息的可靠投 ...

  5. RabbitMQ消息确认机制

    文章目录 1. 事务机制2. Confirm模式2.1 生产者2.1.1 普通Confirm模式2.1.2 批量Confirm模式2.1.3 异步Confirm模式2.2 消费者3. 其他 消费者如何 ...

  6. springboot + rabbitmq发送邮件(保证消息100%投递成功并被消费)

    前言: RabbitMQ相关知识请参考: https://www.jianshu.com/p/cc3d2017e7b3 Linux安装RabbitMQ请参考: https://www.jianshu. ...

  7. (转载)springboot + rabbitmq发送邮件(保证消息100%投递成功并被消费)

    转载自https://www.jianshu.com/p/dca01aad6bc8 一.先扔一张图   image.png 说明: 本文涵盖了关于RabbitMQ很多方面的知识点, 如: 消息发送确认 ...

  8. RabbitMQ入门教程(十二):消息确认Ack

    原文:RabbitMQ入门教程(十二):消息确认Ack 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csd ...

  9. RabbitMQ 消息确认机制

    消息确认机制 在之前异常处理部分就已经写了,对于consumer的异常退出导致消息丢失,可以时候consumer的消息确认机制.重复的就不说了,这里说一些不一样的. consumer的消息确认机制 当 ...

随机推荐

  1. Enterprise Architect 13 : 需求建模 自动命名并计数

    如何给模型中的需求元素配置计数器以自动设置新创建元素的名称和别名: Configure -> Settings -> Auto Names and Counters 设置好后的效果图:

  2. 多线程复习 Rlock ,Condition,Semaphore

    #对于io操作来说,多线程和多进程性能差别不大 #1.通过Thread类实例化 import time import threading def get_detail_html(url): print ...

  3. Java应用调试利器——BTrace教程

    http://www.jianshu.com/p/26f19095d396 背景 生产环境中可能出现各种问题,但是这些问题又不是程序error导致的,可能是逻辑性错误,这时候需要获取程序运行时的数据信 ...

  4. 【BZOJ5010】【FJOI2017】矩阵填数 [状压DP]

    矩阵填数 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 给定一个 h*w 的矩阵,矩阵的行 ...

  5. Spring与MyBatis的整合(山东数漫江湖)

    首先看一下项目结构图: 具体步骤如下: 1.建立JDBC属性文件 jdbc.properties (文件编码修改为 utf-8 ) driver=com.mysql.jdbc.Driver url=j ...

  6. js_在原有的日期上添加天数输出添加后的日期

    开始编码工作也有段时间了,想想没有留下点什么,有点遗憾.学到的一些经验,写写,分享一下.也给自己整理一下. 今天分享一下,在原有的日期上添加天数输出添加后的日期.开始做的时候,简单的思路是,直接用ne ...

  7. 查看服务器是否被DDOS攻击的方法

    伴随着现代互联网络快速发展,更加容易出现被攻击.尤其是ddos攻击已经不在是大网站需要关心的事情了.不少中小型企业,也在遭受ddos攻击.站长对ddos攻击不了解,所以网站被ddos攻击的时候,都不会 ...

  8. udpserver.pl 和 udpclient.pl

    udpserver.pl #!use/bin/perl -w use Socket; #导入Socket库 ,INADDR_ANY);#压入sockaddr_in模式,利用了全局当地压缩地点INADD ...

  9. gradle问题总结与理解(一篇文章带你理解android studio 与gradle 的关系)

    前言:近日在网上找了个很不错的安卓二维码美化,由于下载的项目经常出问题,且不方便依赖使用,因此我想把它写个demo,并把源码发布到jcenter中,修改还是很顺利的,运行项目到手机也没问题,发布遇到了 ...

  10. Educational Codeforces Round 23 补题小结

    昨晚听说有教做人场,去补了下玩. 大概我的水平能做个5/6的样子? (不会二进制Trie啊,我真菜) A. 傻逼题.大概可以看成向量加法,判断下就好了. #include<iostream> ...