rabbitmq消息异常处理

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在使用rabbitmq时,会因为各种原因(网络波动,系统宕机,程序异常等)导致消息发送失败。rabbitmq也提供了相应的处理机制。


提示:以下是本篇文章正文内容,下面案例可供参考

一、rabbitmq消息发送失败处理机制

生产法发送失败
配置回调器。
yml配置开启确认和返回机制
confirm:发送给exchange时的回调,不管是否成功发送给队列。
return:消息没有发送给exchange时的回调。

#成功发送到exchange时的回调
spring.rabbitmq.publisher-confirm-type=correlated
#exchange未发送到队列时回调
spring.rabbitmq.publisher-returns=true

回调函数配置方式

@Component
@Slf4j
public class MyCallBack implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {
    /**
     * 交换机不管是否收到消息的一个回调方法
     *
     * @param correlationData 消息相关数据
     * @param ack             交换机是否收到消息
     * @param cause           未收到消息的原因
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id = correlationData != null ? correlationData.getId() : "";
        if (ack) {
            log.info("交换机已经收到 id 为:{}的消息", id);
        } else {
        //重发处理,可以入库,死信队列处理....
            log.info("交换机还未收到 id 为:{}消息,原因:{}", id, cause);
        }
    }

    //当消息无法路由的时候触发回调方法
    @Override
    public void returnedMessage(ReturnedMessage returned) {
         //重发处理,可以入库,死信队列处理....
        log.error("消息:{},被交换机 {} 退回,原因:{},路由key:{},code:{}",
                new String(returned.getMessage().getBody()), returned.getExchange(),
                returned.getReplyText(), returned.getRoutingKey(),
                returned.getReplyCode());

    }
}

rabbitmqTemplate在启动时注入:

@Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RabbitTemplate.ConfirmCallback confirmCallback;
    @Autowired
    private RabbitTemplate.ReturnsCallback returnsCallback;
    //依赖注入 rabbitTemplate 之后再设置它的回调对象
    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(confirmCallback);
        rabbitTemplate.setReturnsCallback(returnsCallback);
    }

消费者消费失败后处理
通过自动ack+retry配置+私信队列方式实现

spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    listener:
      simple:
#        acknowledge-mode: manual   # 配置该消费者的ack方式为手动
        acknowledge-mode: auto   # 配置该消费者的ack方式为自动
        default-requeue-rejected: false
        #设置消费失败后重发
        retry:
          #重发次数
          max-attempts: 3
          #开启重发
          enabled: true
          # 重试间隔(ms)
          initial-interval: 5000

@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = QUEUE_NAME1, durable = “true”, autoDelete = “false”,
arguments = {@Argument(name = “x-dead-letter-exchange”, value = “dead-exchange”),
@Argument(name = “x-dead-letter-routing-key”, value = “dead-routing-key”),
@Argument(name = “x-message-ttl”, value = “1000”,type = “java.lang.Long”)
}),
exchange = @Exchange(value = “first_exchange”, type = ExchangeTypes.DIRECT),
key = “queue_one_key1”))
public void handleMessage1(Message message, Channel channel) throws IOException {
log.info(“OrderConsumer handleMessage {} , error:”, message);
//模拟消费异常,自动进入私信队列
throw new RuntimeException(“抛出异常,模拟消费失败,触发spring-retry”);
}

/**
 * 死信队列消费者
 *
 * @param data
 * @param channel
 * @throws Exception
 */
@RabbitListener(queues = "dead-queue")
public void consumeDL(String data, Channel channel) throws Exception {
    //处理消费失败的消息
    log.info(">>>> 死信队列消费 tag = {},消息内容 : {}", data);

// channel.basicNack(tag, false, false);
}

通过手动ack+私信队列实现(不要配置retry!!!)

spring.rabbitmq.publisher-returns=true
spring.rabbitmq.listener.simple.acknowledge-mode=manual
    @RabbitListener(queues = CONFIRM_QUEUE_NAME)
    public void receiveMsg(String data, Message message, Channel channel) throws IOException {
        String msg = new String(message.getBody());
        log.info("接受到队列 confirm.queue 消息:{}", msg);
//        throw new RuntimeException("抛出异常,模拟消费失败,触发spring-retry");
        //模拟消费失败,重发n次后仍然失败。调用basicNack 抛给私信队列处理
        channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
    }
 //接收消息
    @RabbitListener(queues = "QD")
    public void receiveD(Message message, Channel channel) throws IOException {
        String msg = new String(message.getBody());
        log.info("当前时间:{},收到死信队列信息{}", new Date().toString(), msg);
    }

总结

rabbitmq消息失败处理需要谨慎对待,因为容易产生资源消耗殆尽的问题!!!

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RabbitMQ 消息丢失的处理方式通常有以下几种: 1. 消息持久化 使用消息持久化机制可以将消息写入磁盘中,即使 RabbitMQ 服务异常退出,也可以保证消息不会丢失。在生产者发送消息时,需要将消息设置为持久化的,而在消费者接收消息时,需要 ACK 确认接收,这样才能保证消息被正确地持久化。如果消息被持久化到磁盘中,但尚未被交付给消费者,那么可以使用 RabbitMQ 的镜像队列机制,将消息复制到多个节点上,从而提高消息的可靠性。 2. 消息确认机制 使用消息确认机制可以保证消息被正确地接收和处理。在消费者接收消息后,需要发送 ACK 确认接收,如果消费者异常退出或者没有发送 ACK 确认接收,那么 RabbitMQ 会重新将消息发送给其他消费者,从而保证消息不会丢失。 3. 设置 TTL 设置 TTL(Time To Live)可以让消息在一定时间内自动过期,从而避免消息过期后一直占用队列的空间。在生产者发送消息时,可以设置消息的 TTL,当消息过期后,RabbitMQ 会将消息自动删除,从而释放队列的空间。 4. 队列长度限制 设置队列长度限制可以限制队列中的消息数量,当队列中的消息数量超过一定的限制时,RabbitMQ 会自动删除最早的消息,从而释放队列的空间。在创建队列时,可以设置队列的最大长度,从而限制队列中消息的数量。 总之,在使用 RabbitMQ 时,需要根据实际场景和需求选择合适的消息传输机制,并且合理地设置消息的 TTL、队列长度限制等参数,从而保证消息的可靠性和一致性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

感恩的心_Yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值