管理网站建设源代码程序,什么是企业网站策划案,单产品网站模板,学习网站开发思路一. 前言最近有很多小伙伴开始找工作#xff0c;在面试时#xff0c;面试官经常会问我们这样一个题目#xff1a;RabbitMQ如何防止重复消费?有很多小伙伴这个时候都在想#xff0c;消息怎么还会重复消费呢???.......所以他们在面试后就跑来问壹哥#xff0c;针对这个比…一. 前言最近有很多小伙伴开始找工作在面试时面试官经常会问我们这样一个题目RabbitMQ如何防止重复消费?有很多小伙伴这个时候都在想消息怎么还会重复消费呢???.......所以他们在面试后就跑来问壹哥针对这个比较高频的题目壹哥就在这里为大家来讲讲MQ防止重复消费的实现方案吧。二. 面试题考点如果面试官是壹哥的话那么我想考察的其实是候选人对技术的基本使用以及在各种实际应用场景中对可能发生的问题的实际处理能力。所以这道题的考点最起码要考虑两点:第一RabbitMQ中消息的重复消费是如何产生的我们首先要发现问题,知道问题产生原因第二针对重复消费问题的处理方案及解决机制。三. 解题分析接下来壹哥就根据上述考点带大家来一起分析这个问题的解题思路。1. RabbitMQ消息重复消费的产生原因根据上图壹哥给大家梳理总结出了消息可能出现重复消费的产生过程如下1. 消费方的业务项目从MQ队列中接收数据2. 接着处理业务3. 业务处理成功后消费方项目给MQ返回ack进行手动确认4. 返回回调执行结果的过程中因为网络抖动等原因回调数据时MQ没有返回成功。所以MQ队列中的数据会再次发给业务项目造成重复消费。2. RabbitMQ消息重复消费的处理方案针对消息的重复消费问题壹哥根据上图总结的解决思路如下1. 监听器接收MQ队列中的数据2. 利用redis的setnx命令以消息唯一id为key以消息内容为value超时时间设置为10秒存入redis中3. 如果能够成功存入说明没有重复消费则处理业务处理完业务后返回ack或者nack确认4. 如果存不进去则说明重复消费直接返回ack确认的回调信息就可以了。3. 解决重复消费的案例代码3.1 发送方测试代码/*** 测试发送* author 千锋壹哥*/
SpringBootTest(classes ProducerApplication.class)
RunWith(SpringRunner.class)
public class TestProducer {Autowiredprivate RabbitTemplate rabbitTemplate;Testpublic void contextLoads() throws IOException {//给消息封装一个唯一id对象CorrelationData messageId new CorrelationData(UUID.randomUUID().toString());//第四个参数: 设置消息唯一idrabbitTemplate.convertAndSend(交换器名字,路由键,千锋壹哥测试MQ重复消费处理,messageId);}
}3.2 接收方测试代码package com.qf.rabbitmq.topic;import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.util.concurrent.TimeUnit;/*** author 千锋壹哥*/
Component
public class Consumer {Autowiredprivate StringRedisTemplate redisTemplate;RabbitListener(queues 队列名字)public void getMessage(String msg, Channel channel, Message message) throws IOException {//0. 获取MessageId, 消息唯一idString messageId (String) message.getMessageProperties().getHeaders().get(spring_returned_message_correlation);//1. 设置key到Redisif(redisTemplate.opsForValue().setIfAbsent(messageId,0, 10, TimeUnit.SECONDS)) {//2. 消费消息System.out.println(接收到消息 msg);//3. 设置key的value为1redisTemplate.opsForValue().set(messageId,1,10,TimeUnit.SECONDS);//4. 手动ackchannel.basicAck(message.getMessageProperties().getDeliveryTag(),false);}else {//5. 获取Redis中的value即可 如果是1手动ackif(1.equalsIgnoreCase(redisTemplate.opsForValue().get(messageId))){channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);}}}
}四. 总结经过上面的分析最后壹哥再给大家总结一下这个问题的完整答案。1.问题产生原因因为消费方和MQ服务器网络闪断等原因造成了接收方接受消息后返回给MQ服务器一个ack确认消息但MQ却没有接收到这就造成了重复消费。2.解决过程利用redis的setnx命令将消费的消息id存入到redis超时时间设置为10秒然后再给mq返回ack。消费前要判断redis中是否存在这个消息id如果不存在说明没有消费过则正常消费如果redis中存在这个消息id则说明产生了重复消费此时直接返回ack不重复执行业务。如果你想知道更详细的解答可以参考壹哥的高薪面试题精讲专栏哦高薪程序员面试题精讲系列125之RabbitMQ怎样保证消息的可靠性、不重复及不丢失?以上就是MQ中消息重复消费的产生原因及解决思路和对应案例现在你知道该怎么解决了吗如果你还有其他疑问可以在评论区给我们留言哦。关注壹哥收获多多