幂等性问题(消息重复消费)、消息丢失 实现

上文讲到幂等性问题(消息重复消费)、消息丢失的逻辑,这次就把实现代码分享一下

生产者
rabbitMq配置文件配置:
 rabbitmq:
    host: rabbitMq地址
    port: rabbitMq端口
    username: rabbitMq用户
    password: rabbitMq密码
    #这个配置是保证提供者确保消息推送到交换机中,不管成不成功,都会回调
    publisher-confirm-type: correlated
    #保证交换机能把消息推送到队列中
    publisher-returns: true
    #虚拟host 可以不设置,使用server默认host
    virtual-host: /
    #这个配置是保证消费者会消费消息,手动确认
    listener:
      simple:
        acknowledge-mode: manual#消息确认方式,none、manual和auto
    template:
      mandatory: true
生产者实现代码
@Autowired
private RabbitTemplate rabbitTemplate;

public void sendMQ(){
//实体,封装信息
Enity enity = new Enity();
enity.setId(id);
enity.setUserName(UserName);
enity.setSex(sex);
enity.setOrderNo(orderNo);
String json=JSON.toJSONString(enity)
//这个correlationData是因为确认机制发送消息时,需要给每个消息设置一个全局唯一id,以区分不同消息,避免ack冲突。
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());

//RabbitMQ提供了类似于回调函数的机制来告诉发送方消息是否发送成功。
//交换机(举例说明)
//RABBITMQ_EXCHANGE
//路由(举例说明)
//RABBITMQ_ROUTING

rabbitTemplate.convertAndSend(RABBITMQ_EXCHANGE, RABBITMQ_ROUTING, json, correlationData);
}
消费者
//RABBITMQ_TOPIC
@RabbitHandler
@RabbitListener(queuesToDeclare = @Queue(RABBITMQ_TOPIC))
public void businessMethods(String json, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
    Enity enity = JSON.parseObject(json, Enity.class);
    String orderNo = enity.getOrderNo();
    boolean states=false;
    try {
        if (redise.exists(orderNo)) {
            String states = redise.get(orderNo);
            if (Func.equals(states,"true")) {
                log.info("消息已被处理过,结束");
                channel.basicAck(tag, true);
                return;
            }
        }
        //处理业务 MQ调用同步方法
        if (Func.isNotEmpty(json)) {
        	//处理业务
            statesType=service.businessMethods(json);
        }
        //设置过期时间
        redise.setEx(orderNo,String.valueOf(statesType),600L);
        //手动Ack
        channel.basicAck(tag, true);
    } catch (Exception e) {
        log.error("消费失败:[{}]", json);
        redise.setEx(orderNo,String.valueOf(statesType),600L);
        //异常后消息会被送回队列再次被监听到继续消费,重试消费默认3次后便不再消费
        Object countObject = redise.get(tag);
        Integer count;
        if (Func.isEmpty(countObject)) {
            count = 0;
        } else {
            String str = JSON.toJSON(countObject).toString();
            count = Integer.valueOf(str);
        }
        try {
          	//requeue = true 放入死信队列
            if (count >= MAX_RETRIES) {
                channel.basicNack(tag, false, false);
            } else {
                //requeue = false 放入消费队列重试消费
                channel.basicNack(tag, false, true);
                count=count + 1;
                bladeRedis.setEx(tag, count , 60L);
            }
        } catch (IOException ioException) {
            log.error(ioException.getMessage(), ioException);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值