聊聊 RabbitMQ 消息可靠性的保证

聊聊 RabbitMQ 消息可靠性的保证


消息可能会出现的不可靠问题:

  • 消息丢失
  • 消息重复
  • 消息积压


1、消息丢失

产生的原因及相应的解决方案

原因一:

​  消息发送出去,但由于网络问题没有成功抵达服务器,造成消息丢失。

解决方案:

​  做好相应的日志记录(将消息信息写入数据库)和容错方法(try-catch 尝试重发、定期扫描数据库将发送失败的消息进行重发)

try{
    
    
    // 业务代码...
    // 将消息信息写入数据库(如:消息id、消息内容、目的地、路由键、类的类型、
    // 消息状态[新建、已发、错误抵达、已抵达])
} catch (Exception e) {
    
    
    // 尝试重发
}

原因二:

​  消息抵达 Broker 时,MQ 宕机,此时消息未完成持久化(未被写入数据库),造成消息丢失。

解决方案:

​  使用 publisher(生产者)的确认机制(ConfirmCallback、ReturnCallback)。

public void initRabbitTemplate(RabbitTemplate rabbitTemplate) {
    
    
        // 设置 消息到达 Broker 的确认回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
    
    
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
    
    
                // 消息成功抵达 Broker
            }
        });

        // 设置 消息到达 Queue 的确认回调
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
    
    
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
    
    
                // 消息未抵达 Queue,持久化失败
                // 消息重发操作...
            }
        });
    }

原因三:

​  consumer(消费者)收到消息,但还没来得及处理消息就宕机了,造成消息丢失。

解决方案:

​  开启手动 ACK 模式。

spring:
  rabbitmq:
    listener:
      simple:
        # 手动 ack
        acknowledge-mode: manual
void messageHandle(Message message, Channel channel) throws IOException {
    
    
	long deliveryTag = message.getMessageProperties().getDeliveryTag();
    // 手动确认消息
    channel.basicAck(deliveryTag, false);
}    


2、消息重复消费

产生的原因及相应的解决方案

原因一:

​  consumer(消费者)消费消息成功,但在回复 ack 时,机器宕机,导致没有成功回复 ack,而 Broker 中的消息状态又重新由 unack 变为 ready,并发送给其它 consumer,导致消息重复消费。

解决方案:

  • 保证业务接口的幂等性(重点);
  • 使用防重报;
  • 查看消息的 redelivered 字段。

原因二(可容忍):

​  consumer 消费消息失败,触发 Broker 的重试机制, 自动将消息重发出去,导致消息重复消费。



3、消息积压

产生的原因及相应的解决方案

原因:

  • consumer 宕机积压,导致消息积压;
  • consumer 消费能力不足,导致消息积压;
  • publisher 产生消息的速度大于 consumer 消费消息的速度,导致消息积压。

解决方案:

  • 上线更多的 consumer;
  • 上线专门的队列消费服务,先将消息批量取出,存入数据库,待系统空闲时再从数据库取出消息进行处理。

猜你喜欢

转载自blog.csdn.net/weixin_51123079/article/details/127307243