RabbitMQ-消费者"未处理完的消息"丢失
一个关于客户端(消费者)开启自动应答,重启后"未处理消息丢失"的小坑。(主要是对RabbitMQ理解不够)
首先,申明一下: 本文所谓的 "丢失消息" 不是指服务器宕机、重启等原因导致内存中消息丢失,也就是说不是关于消息持久化的问题。
使用C# 编写测试。
问题表象: 消费者开启自动应答,某时,消费者掉线(关闭/崩溃等),届时重启消费者,发现消费者未处理完的消息丢失。
条件: 服务器不宕机、不重启,只有一个消费者、一个生产者。
消息流向: 消息--->生产者--->交换器--->队列--->消费者
问题的处理: 消费者开启手动应答,若再出现之前情况,消息不丢失。
先给个代码。
生产者代码如下:
static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
//申明广播类型交换器
channel.ExchangeDeclare(exchange: "ex1", type: "fanout");
//申明队列
channel.QueueDeclare(queue: "test1",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null); int count = 0; while (true)
{
count++;
var body = Encoding.UTF8.GetBytes(count.ToString());
//向key为 p 的交换器 ex1 上推数据
channel.BasicPublish(exchange: "ex1",
routingKey: "p",
basicProperties: null,
body: body); Console.WriteLine($"send msg {count}");
System.Threading.Thread.Sleep(1000);
} }
}
消费者代码如下(开启自动应答):
static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
//队列与交换器绑定
channel.QueueBind(queue: "test1",
exchange: "ex1",
routingKey: "p"); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body); Console.WriteLine($"收到消息 -- {message}"); System.Threading.Thread.Sleep(2000);
}; channel.BasicConsume(queue: "test1",
autoAck: true,
consumer: consumer); Console.ReadLine();
} }
*交换器、队列必须先申明,两样都存在后才能进行绑定。
生产者向队列推送消息,队列中展现状态为ready的数据就是未被消费的消息。
推送90个消息:
队列中存了90个未应答的消息
打开消费者:
发现现在消息已经全部被自动应答,队列已清空。
再启动消费者:
如预料,空空一片。
小结 :开启消费者(开启自动应答),发现队列中状态为Ready的消息全部被应答,队列中状态为Ready的消息清空,不等消费者处理完这些消息,关闭消费者,然后再开启消费者,消费者不会再收到消息,出现消费者"未处理"完的消息丢失的问题。
同之前先屯90个消息。
然后关闭自动应答。
开启消费者:
消息状态一次性全部变成unacked。 因为没有写手动处理消息的逻辑,所以unacked状态的消息不会变少。
然后关闭消费者:
RabbitMQ 未删除无应答的消息,消息重新转为Ready状态,继续等待连接消费者处理。
再开启消费者:
没有出现丢失未处理完消息的情况。
小结:开启消费者(关闭自动应答),发现队列中状态为Ready的消息状态全部转变为unacked,队列中状态为ready的消息清空,随消费者应答,队列中状态为unacked的消息逐渐减少,关闭消费者,发现队列中状态为unacked的消息重新改变回ready状态,
结论:
关闭自动应答可避免这种消息"丢失的情况"。
另外在开启自动应答 ack=true 的情况下,需要保证一定有消费者在线,才能保证消息都被接收处理。开启手动应答必然消耗更多资源,因为 RabbitMQ 需要根据应答标号去删除队列中对应的消息。
以上仅个人理解,若有错误,欢迎指正~
RabbitMQ-消费者"未处理完的消息"丢失的更多相关文章
- RabbitMQ处理未被路由的消息
我们经常使用消息队列进行系统之间的解耦,日志记录等等.但是有时候我们在使用 RabbitMQ时,由于exchange.bindKey.routingKey没有设置正确,导致我们发送给交换器(excha ...
- RabbitMQ防止消息丢失
转载请注明出处 0.目录 RabbitMQ-从基础到实战(1)— Hello RabbitMQ RabbitMQ-从基础到实战(3)— 消息的交换 1.简介 RabbitMQ中,消息丢失可以简单的分为 ...
- RabbitMQ,RocketMQ,Kafka 事务性,消息丢失和消息重复发送的处理策略
消息队列常见问题处理 分布式事务 什么是分布式事务 常见的分布式事务解决方案 基于 MQ 实现的分布式事务 本地消息表-最终一致性 MQ事务-最终一致性 RocketMQ中如何处理事务 Kafka中如 ...
- RabbitMQ-从基础到实战(2)— 防止消息丢失
转载请注明出处 1.简介 RabbitMQ中,消息丢失可以简单的分为两种:客户端丢失和服务端丢失.针对这两种消息丢失,RabbitMQ都给出了相应的解决方案. 2.防止客户端丢失消息 如图,生产者P向 ...
- RabbitMQ:消息丢失 | 消息重复 | 消息积压的原因+解决方案+网上学不到的使用心得
前言 首先说一点,企业中最常用的实际上既不是RocketMQ,也不是Kafka,而是RabbitMQ. RocketMQ很强大,但主要是阿里推广自己的云产品而开源出来的一款消息队列,其实中小企业用Ro ...
- rabbitmq 重复ACK导致消息丢失
rabbitmq 重复确认导致消息丢失 背景 rabbitmq 在应用场景中,大多采用工作队列 work-queue的模式. 在一个常见的工作队列模式中,消费者 worker 将不断的轮询从队列中拉取 ...
- RabbitMQ消息丢失问题和保证消息可靠性-消费端不丢消息和HA(二)
继续上篇文章解决RabbitMQ消息丢失问题和保证消息可靠性(一) 未完成部分,我们聊聊MQ Server端的高可用和消费端如何保证消息不丢的问题? 回归上篇的内容,我们知道消息从生产端到服务端,为了 ...
- 解决RabbitMQ消息丢失问题和保证消息可靠性(一)
原文链接(作者一个人):https://juejin.im/post/5d468591f265da03b810427e 工作中经常用到消息中间件来解决系统间的解耦问题或者高并发消峰问题,但是消息的可靠 ...
- 如何处理RabbitMQ 消息堆积和消息丢失问题
消息堆积 解决方案: 增加消费者或后台相关组件的吞吐能力 增加消费的多线程处理 根据不同的业务实现不同的丢弃任务,选择不同的策略淘汰任务 默认情况下,RabbitMQ消费者为单线程串行消费,设置并行消 ...
随机推荐
- html5 替换 历史 记录
history.replaceState({url:"/admin/index"},null,"/admin/index"); url 是 需要替换的路径
- Markdown 简单标签语言
Markdownhttps://www.cnblogs.com/ixysy/p/6236782.html Markdown基本语法https://www.jianshu.com/p/191d1e21f ...
- 【ACM】喷水装置
喷水装置(一) 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 现有一块草坪,长为20米,宽为2米,要在横中心线上放置半径为Ri的喷水装置,每个喷水装置的效果都会让以 ...
- CentOS 7: ping Name or service not known
解决方法 cd到/etc/sysconfig/network-scripts/ 修改ifcfg-*(*代表的内容可通过ifconfig查看)中的ONBOOT=yes reboot ifcfg-ens3 ...
- 宋宝华:swappiness=0究竟意味着什么?
http://mp.weixin.qq.com/s/BixMISiPz3sR9FDNfVSJ6w 本文解释swappiness的作用,以及swappiness=0究竟意味着什么. 内存回收 我们都知道 ...
- 车牌号校验js
var regExp = /(^[\u4E00-\u9FA5]{1}[A-Z0-9]{6}$)|(^[A-Z]{2}[A-Z0-9]{2}[A-Z0-9\u4E00-\u9FA5]{1}[A-Z0-9 ...
- 牛客网Java刷题知识点之基本类型、引用类型
不多说,直接上干货! byte-short-int-long,方便识记.
- Kotlin容器
1. 容器 可变/不可变 List<out T> 只读list; MutableList<T>; Set<out T>/MutableSet<T> Ma ...
- 2019年我的nodejs项目选型
选型项目比较激进.发现基于 go 语言的工具变多了.
- CF1136D Nastya Is Buying Lunch
思路: 1. 最终答案不超过能与Nastya“直接交换”的人数. 2. 对于排在j前面的i,如果i和i-j之间(包括j)的每个人都能“直接交换”,j才能前进一步. 实现: #include <b ...