RabbitMQ消息确认(ACK)模拟

本文介绍了RabbitMQ的消息确认(ACK)机制,防止数据丢失。通过模拟实验展示了如何在Spring AMQP和RabbitMQ Client中开启ACK模式,配置并发性和预读取数量。在异常情况下,如空指针异常和消息为空时,未正确反馈ACK会导致消息堆积,甚至阻塞消费。最后,建议通过调整并发性和预读取数量以及确保正确的ACK逻辑来避免阻塞问题。
摘要由CSDN通过智能技术生成

RabbitMQ消息确认(ACK)机制

一、概念

在MQ接受消息处理过程中,消费者进程在处理消息时发生异常,那么这条消息就没有完成消费,数据就会丢失,为了确保数据不会丢失,RabbitMQ支持消息确认-ACK

ACK机制是在消费者进程从RabbitMQ收到消息处理完成后,反馈给RabbitMQ,RabbitMQ收到反馈后才能将此消息从队列中删除。如果出现消费者服务器或者进程宕机,没有及时反馈ACK,那么RabbitMQ就不会将消息删除,并重新返回队列。

但是如果出现业务逻辑出错,也就是忘记或者逻辑错误没有反馈ACK,那么消息就会一直堆积在内存中,在RabbitMQ中表示消息显示Unack,达到上限后,应用将无法消费队列中消息,单个应用进程上限是通道数量channlCount * 预读取prefetchCount (channlCount通道数量由Concurrency,max-concurrency决定)

 

二、模拟实验

1、MQ连接配置

开启ACK模式

方式一、使用Spring AMQP连接框架,在Spring连接工厂或者自定义的连接工厂中设置, acknowledge-mode:manual

方式二、使用RabbitMQ Client在basicConsume接收消息方法中定义

消费者数量

cocurrency:5

max- cocurrency:10

设置预读取

prefetch:5

2、代码示例

连接工厂配置

 

接收代码:监听接收队列名称为“queue”队列,打印message body模拟耗时3秒。处理完成后手动ACK并打印消息tag,如出现错误反馈NACK,应用于单条消息,不requeue销毁或者进入死信。

 

发送队列:定义发送通道,定义队列queue并发送message,循环i次间隔1秒。

 

测试正常效果:发送30条消息并接收

通道状态(发送)

队列状态

通道状态(接收):与我们配置的一样5个消费通道,每个预处理5条

队列状态:由于我处理时间存在3秒的等待,所以出现图表统计中体现Unacked数量

接受应用日志:与我们预计的一样,5个通道每批次处理5条,每批次tagid一致

异常测试一:模拟空指针异常处理逻辑,异常被捕获

发送与之前一样,接受效果如下,由于异常捕获后应答Nack所以队列中的消息也可以被处理,不会堆积

日志中显示报错,但能处理消息

如果定义死信队列,可以在死信队列找到消息,并可以看出原因

异常测试二:模拟接受消息为空,对消息处理出现空指针异常,异常被捕获或者应答时候出现异常,比如Message出现null或者io Exception未捕获,就是方法逻辑写在try/catch外,Message异常也会引起问题,比如没有定义finally,将应答写在finally中。

两者现象都一致如下,也就是当逻辑出现问题没有正常应答,消息就在通道中,也就是消费到通道个数5*预读取prefetch5=25个的时候,就出现阻塞,无法消费后续Ready的消息

 

进程重启后这些unacked消息会回到队列,观察到Unacked数字一下归零,Ready数字变成30

如果在阻塞时,启动新的消费者,Ready的消息可以被消费,Unacked消息无法被消费直到应答或者应用进程中断

 

三、总结

调整cocurrency和prefetch大小可以缓解阻塞问题的发生频率,但要根本解决阻塞问题还需要从逻辑上完成应答处理。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值