RabbitMQ中使用Redis解决消费者重复消费的问题

为什么解决重复消费的问题?

  • 生成者在发送消息时可能因为网络或其他原因导致消息发送延时,补偿机制会重新发送相同的消息
  • 消费者消费异常
解决思路
  • 生产者发送消息时携带一个唯一的id
  • 消费者每次消费前先判断一下在redis中是否在id,不存在就消费,消费完之后就把id存储到redis中
代码实现
  • 消费者发送消息携带id
    @GetMapping("/directredis")
    public String sendMsgRedis(@RequestParam Map<String,Object> msg){
        try{
//            模拟相同的key,实际业务使用业务id
            String uuid = "keykeykey";
            Message message = MessageBuilder.withBody(JSON.toJSONString(msg).getBytes()).setMessageId(uuid).build();
            rabbitTemplate.convertAndSend("EmailExchange","emailRouting",message);
            return "ok";
        }catch (Exception e){
            e.printStackTrace();
            return "连接异常....";
        }
    }
  • 消费者的接收(redisCacheUtil在文章最后给出)
    @RabbitListener(queues = "emailQueue")
    public void listenerMqAtRedis(Message message){
        String messageId = message.getMessageProperties().getMessageId();
//        判断messageId在Redis中是否存在
        if(messageId != null && !redisCacheUtil.exists(messageId)){
//            没有重复消息
            System.out.println(">>>>>>>>>>>>开始发送邮件:"+message.getBody().toString());
            redisCacheUtil.setKey(messageId,true);
        }else{
            System.out.println(">>>>>>>>>>>>已经消费..........");
        }
    }
测试

先准备几条id相同的消息

在这里插入图片描述

启动消费者进行接收,可以看到消息只消费了一次。

在这里插入图片描述

redisCacheUtil

package com.wcong.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 * @author wcong
 * @version 1.0
 * @date 2020-07-31 8:11
 */
@Component
public class RedisCacheUtil {

    @Autowired
    private RedisTemplate<String,Object>  redisTemplate;

    /**
     * 写入缓存
     * @param key
     * @param val
     * @return
     */
    public boolean setKey(final String key,Object val){
        boolean result = false;
        try {
            redisTemplate.opsForValue().set(key,val);
            result = true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 写入缓存,可以设置过期时间
     * @param key
     * @param val
     * @return
     */
    public boolean setKey(final String key,Object val,Long time){
        boolean result = false;
        try {
            redisTemplate.opsForValue().set(key,val,time);
            result = true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 判断key是否存在
     * @param key
     * @return
     */
    public boolean exists(final String key){
        try{
            return redisTemplate.hasKey(key);
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 读取缓存
     * @param key
     * @return
     */
    public Object getVal(final String key){
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除缓存
     * @param key
     */
    public void remove(final String key){
        redisTemplate.delete(key);
    }

    /**
     * 批量删除缓存
     * @param keys
     */
    public void remove(String... keys){
        for (String key : keys) {
            redisTemplate.delete(key);
        }
    }

}

  • 设置redis的序列化方式
package com.wcong.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author wcong
 * @version 1.0
 * @date 2020-07-31 8:18
 */
@Configuration
public class RedisConfig {

    /**
     * 设置redis的序列化方式
     * @return
     */
    @Bean
    @Primary
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值