rabbitmq消费消息:结合redis保证消息不被重复消费

11 篇文章 0 订阅
3 篇文章 0 订阅
  • 通用解决方案是在消息实体中添加全局唯一的id,例如 msg_id(消息ID),在代码中保证消息的幂等性,
  • 消费者在收到消息之后,根据 msg_id 从缓存或者数据库中查询是否存在已有消息;
  • 如果不存在已有消息,那么消费之后,将 msg_id 对应的消息实体或者序列化对象写入缓存或者数据库;
  • 如果存在已有消息,说明这条消息已被消费过,丢弃消息并且打一条告警日志。
  • 并且可以根据重复消费的容忍程度以及性能要求选择使用缓存还是使用数据库,
  • 如果对判断的速度要求高,可以使用 Redis 作为缓存;
  • 如果对判断的稳定性和鲁棒性要求高,使用数据库存储消息实体,同时将 msg_id 作为数据库表的唯一键,插入重复记录一定会抛出异常,避免数据库因为并发问题产生脏数据,保证了消息消费的不可重复性。
  • 这里使用stringRedisTemplate.opsForHash()保证消息不被重复消费
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue(value = "queue.name.user", declare = "true"), // 创建info队列,declare默认队列持久化
                    key = {"route.user"}, // 路由key
                    exchange = @Exchange(type = "direct", name = "exchange-directs-user")
            )})
    public void receive12211(Message message, Student student, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {
        System.out.println("message:"+message);
        MessageProperties messageProperties = message.getMessageProperties();
        long tag = deliveryTag;
        Map<String, Object> headers = messageProperties.getHeaders();
        String messageId = headers.get("spring_returned_message_correlation").toString();
        System.out.println("message_id: "+messageId);
        if(stringRedisTemplate.opsForHash().entries("rabbitmq_log").containsKey(messageId)){
            //redis中包含该key,说明已经被消费过了
            System.out.println(messageId+"消息已经被消费过一次");
            //确认消息已被消费
            channel.basicAck(tag,false);
            return;
        }
        try {
            System.out.println("路由模式message1 = " + student);
            stringRedisTemplate.opsForHash().put("rabbitmq_log",messageId,"v");
            channel.basicAck(tag,false);
            System.out.println(messageId+"消息消费成");
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("消息消费异常");
            channel.basicNack(tag,false,true);
        }
    }
server:
  port: 8071

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: admin
    password: 123456
    virtual-host: /ems
    template:
      retry: #重试,消息发送失败会重试
        enabled: true # 开启重试
        initial-interval: 10000ms  #第一次十秒重试
        max-interval: 80000ms  #最后一次是八秒重试
        multiplier: 2  #重试翻倍率
    publisher-confirms: true #发送者开启 confirm 确认机制
    publisher-returns: true  # 发送者开启 return 确认机制
    listener:
      simple:
        acknowledge-mode: manual #开启手动ack

  datasource:
    url: jdbc:mysql://localhost:3306/one?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&AllowPublicKeyRetrieval=True
    username: root
    password: root


  redis:
    host: localhost
    port: 6379
    password:


mybatis-plus:
  mapper-locations: classpath*:com/test/mapper/xml/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
  type-aliases-package: com.test.domain

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值