RabbitMQ如何保证消息不被重复消费

前言:

正常情况下,消费者在消费消息后,会给消息队列发送一个确认,消息队列接收后就知道消息已经被成功消费了,然后就从队列中删除该消息,也就不会将该消息再发送给其他消费者了。不同消息队列发出的确认消息形式不同,RabbitMQ是通过发送一个ACK确认消息。但是因为网络故障,消费者发出的确认并没有传到消息队列,导致消息队列不知道该消息已经被消费,然后就再次消息发送给了其他消费者,从而造成重复消费的情况。

其实重复消费不可怕,可怕的是你没考虑到重复消费之后,怎么保证幂等性。假设你有个系统,消费一条往数据库里插入一条,要是你一个消息重复两次,不就插入了两条,这数据就错了。但是你要是消费到第二次的时候,自己判断一下已经消费过了,直接扔了,不就只保留了一条数据。

幂等性,通俗点说,就一个数据,或一个请求,给你重复来多次,你得确保对应的数据不会改变,不能出错。

重复消费问题的解决思路是:保证消息的唯一性,即使多次传输,也不让消息的多次消费带来影响,也就是保证消息等幂性;幂等性指一个操作执行任意多次所产生的影响均与一次执行的影响相同

具体解决方案如下:

(1)改造业务逻辑,使得在重复消费时也不影响最终的结果。例如对SQL语句: update t1 set money = 150 where id = 1 and money = 100; 做了个前置条件判断,即 money = 100 的情况下才会做更新,更通用的是做个 version 即版本号控制,对比消息中的版本号和数据库中的版本号。

(2)基于数据库的的唯一主键进行约束。消费完消息之后,到数据库中做一个 insert 操作,如果出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。

(3)通过记录关键的key,当重复消息过来时,先判断下这个key是否已经被处理过了,如果没处理再进行下一步。. 生产者发送每条数据的时候,里面添加一个全局唯一的id, 消费者消费到消息后, 先根据消息id去redis中查询,如果redis不存在,就处理消息,然后将消息id写入redis。如果redis中存在,说明消息已经消费过,就不用处理。

① 通过数据库:比如处理订单时,记录订单ID,在消费前,去数据库中进行查询该记录是否存在,如果存在则直接返回。

② 使用全局唯一ID,再配合第三组主键做消费记录,比如使用 redis 的 set 结构,生产者发送消息时给消息分配一个全局ID,在每次消费者开始消费前,先去redis中查询有没有消费记录,如果消费过则不进行处理,如果没消费过,则进行处理,消费完之后,就将这个ID以k-v的形式存入redis中(过期时间根据具体情况设置)。

相关推荐
2501_941882481 小时前
互联网分布式系统中的性能优化工程实践与多语言示例随笔分享
kafka·rabbitmq
2501_941871452 小时前
从接口限流到全链路流控的互联网工程语法构建与多语言实践分享
kafka·rabbitmq
马达加斯加D3 小时前
系统设计 --- 使用消息队列解决分布式事务
分布式
2501_941865634 小时前
从微服务链路追踪到全链路可观测的互联网工程语法实践与多语言探索
rabbitmq·memcached
遇见火星4 小时前
RabbitMQ 高可用:HAProxy 负载均衡实战指南
分布式·消息队列·rabbitmq·负载均衡·haproxy
2501_941804325 小时前
在东京智能地铁场景中构建实时列车调度与高并发乘客流数据分析平台的工程设计实践经验分享
rabbitmq·memcached
Blossom.1185 小时前
基于多智能体协作的自动化数据分析系统实践:从单点工具到全流程智能
运维·人工智能·分布式·智能手机·自动化·prompt·边缘计算
回家路上绕了弯6 小时前
MDC日志链路追踪实战:让分布式系统问题排查更高效
分布式·后端
qq_12498707536 小时前
基于Hadoop的黑龙江旅游景点推荐系统的设计与实现(源码+论文+部署+安装)
大数据·hadoop·分布式·python·信息可视化
2501_941807266 小时前
从任务调度到分布式作业管理的互联网工程语法实践与多语言探索
eureka·rabbitmq