RabbitMQ消息丢失、积压如何处理

198 阅读3分钟

1.为什么产生消息堆积

大多是因为Consumer出问题了,没有及时发现,或者故障恢复需要较长的时间,导致大量消息积压在MQ中。

消息积压处理

总结起来解决方案大体包括:

  • 增加消费者的数量 - 添加机器
  • 提高消费者的消费效率 - 可以使用批量消息处理提高消费者处理效率
  • 先将消息从MQ中释放出来,再缓慢的进行消费 - 使用临时消费者将消息持久化(这个需要根据业务场景看是否符合)

消息丢失

Producer如何防止消息丢失

RabbitMQ宕机,生产者发送失败

在业务代码中添加容错机制,在消息发送失败时,可以先将消息持久化到数据库,然后等待RabbitMQ可用时,再进行消息发送。

网络波动导致消息丢失

在producer 发送消息到 RabbitMQ,由于网络原因导致生产者认为消息已经发送,但是RabbitMQ并没有接收到消息,而导致的消息丢失场景。 可以使用RabbitMQ提供的事务/Confirm机制,因为Confirm机制从执行效率上比事务要高,所以我们一般使用Confirm来保证不会因为网络问题而导致的消息丢失。

RabbitMQ宕机,在内存中的消息丢失

因为Rabbitmq发送消息默认是异步发送的,所以在这种情况下我们是无法感知到消息是否确认发送到了exchange中的。

  • 确认机制(Confirm机制): RabbitMQ 提供了 Confirm 机制,允许生产者异步地获得消息是否已经发送到 Broker。通过配置 RabbitTemplate 的 setConfirmCallback,可以注册一个 ConfirmCallback 来获取确认结果。
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
    if (ack) {
        // 消息成功发送到 Exchange
        System.out.println("Message sent successfully to Exchange");
    } else {
        // 消息发送失败
        System.err.println("Failed to send message to Exchange: " + cause);
    }
});

rabbitTemplate.convertAndSend(exchangeName, routingKey, message);

  • Return Callback: 如果消息发送到 Exchange 时无法路由到任何队列,RabbitMQ 会触发 Return Callback。通过配置 RabbitTemplate 的 setReturnCallback,可以注册一个 ReturnCallback 来获取这种情况的通知。
rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
   System.err.println("Message returned: " + message);
   // 处理返回的消息,可能是消息发送到 Exchange 但没有匹配的队列
});

rabbitTemplate.convertAndSend(exchangeName, routingKey, message);

以上就是保证生产者在消息发送时保证消息发送到RabbitMQ的解决方法。注意,使用 Confirm 机制需要在 RabbitMQ Broker 端启用 Confirm。这样,即使 RabbitMQ 在消息发送后挂掉,你也能在程序中感知到消息是否成功发送到了 Exchange。

Consumer如何防止消息丢失

当消费者接收到消息时,消费者发生了故障,导致消息从队列中移除,但是也没有被消费者正常消费所导致的消息丢失问题,我们可以使用RabbitMQ提供的手动ACK。

ACK,只有消费者和RabbitMQ确认消息被正常消费,队列才会移除该消息。

但是也要注意,并不是所有的消息消费失败都不进行消息确认,如果消息本身有问题,我们也需要做相应的容错处理。否则就会导致一直消费失败,从而导致队列中的消息堆积。