【夯实RabbitMQ】如何保证消息不被重复消费?如何保证消息可靠传输?
目录
一、如何保证消息不被重复消费?
消息大部分情况下是要对数据库造成影响的。重复消费的问题解决办法要看具体的业务。
业务1:如果一条消息对应插入一条数据到数据库中,那么可以通过主键先查看数据库中是否已经插入了这条数据。
如果已经插入就不要重复插入了。可以通过为数据库中增加唯一索引的方式来控制重复插入。
或者更新一下数据库中的数据,这个要看具体的业务。
业务2:如果消息有唯一键,可以考虑把消息的唯一键,比如订单号,存放到Redis中,并设置一个过期时间。
过期时间长短也要结合具体的业务场景。
二、如何保证消息可靠传输
消息丢失可能会出现以下三种数据丢失问题: (1)生产者弄丢了数据(2)MQ弄丢了数据(3)消费者弄丢了数据
(1)生产者弄丢了数据
第一种解决方案是使用RabbitMQ的事务模式,不过这种方案是同步的,非常耗性能,一般不使用。
第二种解决方案是使用confirm模式。生产者开启confirm模式后,每次的消息都会被分配一个id,然后写入到RabbitMQ中。RabbitMQ会响应一个ack代表消息已经成功写入MQ中。如果是nack,那么代表没有发送到MQ中失败,会触发回调接口。
可以在这个回调接口里面重新发送消息。
confirm模式是异步的,在发完一个消息的后可以再发送另外的消息。RabbitMQ 接收了之后会异步回调你的一个接口通知你这个消息接收到了。
(2)RabbitMQ 弄丢了数据
如何防止MQ把消息弄丢了,那么就要支持持久化。包括持久化路由器、队列、消息,这样在重启的时候能够恢复这些数据。
发送消息的时候将消息的 deliveryMode
设置为 2,就是将消息设置为持久化的。(默认就是2)
创建队列持久化
创建路由器持久化
(3)RabbitMQ 弄丢了数据
消费端刚接收到消息,然后系统就不可用了。如果是自动ack,那么MQ就认为消费端已经成功消费这条消息,但是实际上还没有来得及消费。所以必须关闭 RabbitMQ 的自动 ack。如果消费消息失败,那么会把消息重新退回MQ中,由MQ将此消息分配给其它消费者。
参考文档:RabbitMQ高可用
springboot整合rabbitMQ---生产者消息确认机制
MQ中间件-rabbitmq-生产者如何确保消息的不丢失(SpringBoot2.0版本)