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确认消息被正常消费,队列才会移除该消息。
但是也要注意,并不是所有的消息消费失败都不进行消息确认,如果消息本身有问题,我们也需要做相应的容错处理。否则就会导致一直消费失败,从而导致队列中的消息堆积。