RabbitMQ——03消息处理

1. RabbitMQ 的消息持久化处理

        消息的可靠性是 RabbitMQ 的一大特色, 那么 RabbitMQ 是如何保证消息可靠性的呢——消息持久化

我们先来看个现象

新建两个项目,一个消费者一个生产者,设置queue的autoDelete为true,生产者循环发送消息,然后,运行消费者,然后运行生产者,如图;

info队列开始接收消息,再看管理台,如图:

两个队列,error和info,其中info队列在运行中并接收消息。

然后,我们关闭消费者,关闭之前观察控制台打印信息,如图,关闭的时候,消息接收到了8,

然后,在看管理台,发现info和error队列消失了如图:

接着,重启消费者,如图:

消费者接收到的消息是从29开始,也就是说9-28的消息丢失了。这是为什么了?很明显的,因为当消费者停止的时候,rabbitMQ的队列列表中已经不存在了info和error队列了,所以生产者发送的消息就成了游魂,无处安放,从而导致了消息的丢失,所以要解决这个问题,首要的任务就是保证消费者关闭的时候,rabbitMQ对应的队列不被删除就可以了。我们发现,在消费者配置中@Queue有一个属性autoDelete,我们设置为true,如图;

我们尝试着将info服务的queue的autoDelete为false,如图:

在运行消费者,然后,关闭消费者,如图:

消息在71的时候关闭了,再看管理台,info队列还在运行,但是error队列已经消失了,同时info的features没有AD(自动删除)标志了。如图:

重启消费者服务,消息在一瞬间从72开始发出来了,如图:

这样消息就没有丢失了。

总结:消息的持久化处理就是将queue的autoDelete设置为false

autoDelete 属性

我们发现autoDelete不但在@queue注解存在,在@Exchange中也有,两者有什么区别了?

1)@Queue: 当所有消费客户端连接断开后, 是否自动删除队列 true: 删除 false: 不删除

2)@Exchange: 当所有绑定队列都不在使用时, 是否自动删除交换器 true: 删除 false: 不删除

所以,两者都可以设置autoDelete=false达到消息持久化的目的

2. RabbitMQ 中的消息确认 ACK 机制

2.1 什么是消息确认ACK

        如果在处理消息的过程中,消费者服务器在处理消息的时候出现异常,那么,可能这条正在处理的消息就没有完成消息消费,数据就会丢失,为了确保数据不会丢失,RabbitMQ支持消息确认——ACK

2.2 ACK消息确认机制

        ACK机制是消费者从RabbitMA收到消息并处理完成后,反馈给RabbitMQ,RabbitMQ收到反馈后才将此消息从队列中删除。

1)如果一个消费者在处理消息的时候出现网络不稳定、服务器异常等现象,那么就不会有ACK反馈,RabbitMQ会认为这个消息没有被正常消费,从而会将队列重新放到队列中。

2)如果在集群的情况下,RabbitMQ会立即将这个消息推送给这个在线的其他消费者,这种机制保证了在消费者服务端故障的时候,不丢失任何消息和任务。

3)消息永远不会从RabbitMQ中删除,只有当消费者正确发送ACK反馈,RabbitMQ确认收到后,消息才会从RabbitMQ服务器的数据中删除

4)消息的ACK确认机制默认是打开的。

2.3 ACK机制的开发注意事项

        如果忘记了ACK,那么后果很严重。当Consumer退出的时候,Message会一直重新分发,然后RabbitMQ会占用越来越多的内存,由于RabbitMQ会长时间运行,因此这个“内存泄漏”是致命的。

2.4 ACK的解决方法

我们先来通过一个实际现象来深刻的了解ACK问题

1)创建消费者工程,在消息处理中手动制造一个异常,如图:

2)运行消费者和生产

如图所示:

系统会一直运行,一直报错,同时消息会一直发送,在看管理台,如图:

队列中的消息不停的增加,一旦时间长了之后,很容易造成内存泄漏。

那么这个问题怎么解决了?

2.4.1 通过异常处理解决

如图:

再次运行消费者,就不会出现一直发送消息的情况了,在看管理台,如图:

消息被正常消费了,这样不会产生内存泄漏问题。

2.4.2 通过消息重试次数限定解决问题

        在消费者服务,通过设置重试次数限制,可以达到当rabbitMQ发送消息的时候,可以根据我们配置的重试次数来重复发送消息,当程序遇到异常,rabbitMQ发送指定次数的消息之后,还没有ACK确认返回,就不会再次发送了。

在配置文件中开启重试:

#开启重试
spring.rabbitmq.listener.retry.enabled=true
#重试次数, 默认为 3 次
spring.rabbitmq.listener.retry.max-attempts=5

注意:这里的key是给spring读的,是固定值。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值