RabbitMQ消息可靠性三板斧

RabbitMQ消息可靠性三板斧

生产环境消息不能丢,三个环节都要保证:

scss 复制代码
生产者 --(Confirm/Return)--> Broker --(持久化)--> 队列 --(手动ACK)--> 消费者

1. 生产者确认(Confirm)

application.yml 开启:

yaml 复制代码
spring:
  rabbitmq:
    publisher-confirm-type: correlated

配置回调:

typescript 复制代码
@Configuration
public class RabbitConfig implements RabbitTemplate.ConfirmCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct
    public void init() {
        rabbitTemplate.setConfirmCallback(this);
    }

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            System.out.println("消息成功到达 Exchange");
        } else {
            System.err.println("消息丢失: " + cause);
            // TODO: 补偿重发或记录数据库
        }
    }
}

2. 消息退回(Return)

当 Exchange 无法路由到 Queue 时触发:

typescript 复制代码
@Configuration
public class RabbitConfig implements RabbitTemplate.ReturnsCallback {

    @PostConstruct
    public void init() {
        rabbitTemplate.setReturnsCallback(this);
    }

    @Override
    public void returnedMessage(ReturnedMessage returned) {
        System.err.println("路由失败: " + returned.getMessage());
        // TODO: 报警或转存
    }
}

发消息时指定 mandatory = true

arduino 复制代码
rabbitTemplate.convertAndSend(
    "exchange", "routingKey", msg,
    message -> message,  // MessagePostProcessor
    new CorrelationData("id-001")
);

3. 队列与消息持久化

typescript 复制代码
@Bean
public Queue durableQueue() {
    // durable=true 队列持久化
    return QueueBuilder.durable("durable.queue").build();
}

消息持久化:

ini 复制代码
MessageProperties props = new MessageProperties();
props.setDeliveryMode(MessageDeliveryMode.PERSISTENT); // 2 = 持久化

Message message = new Message("hello".getBytes(), props);
rabbitTemplate.convertAndSend("exchange", "key", message);

4. 消费者手动 ACK

application.yml

yaml 复制代码
spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: manual  # 手动确认
        prefetch: 1               # 每次只取1条,处理完再取下一条

消费者代码:

java 复制代码
@Component
public class AckConsumer {

    @RabbitListener(queues = "durable.queue")
    public void receive(Message message, Channel channel) throws IOException {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            String body = new String(message.getBody());
            System.out.println("处理: " + body);
            // 业务逻辑...
            
            // 手动确认
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            // 拒绝并重新入队(根据业务决定是否重试)
            channel.basicNack(deliveryTag, false, true);
        }
    }
}

小结:Confirm 防丢失到 Exchange,Return 防路由失败,持久化防 Broker 重启丢数据,手动 ACK 防消费者处理失败丢消息。四者结合,消息可靠性基本稳了。

相关推荐
GreenTea7 小时前
深度解读 Anthropic 多智能体报告:更强的模型 ≠ 更好的协调
前端·后端·算法
风流 少年7 小时前
Spring AI 2.0:Memory
java·后端·spring
万少8 小时前
给 DeepSeek Harness 装个"应用商店":一条命令,595 个插件随你逛
前端·javascript·后端
IT_陈寒12 小时前
Python的GIL让我多写了500行代码
前端·人工智能·后端
IT爱学堂13 小时前
精讲软件设计师(软考中级)一站式通关课_实战课程_慕课网
后端
战天战地站房顶13 小时前
在 Windows Docker 中部署 PostgreSQL 17 + pgvector 完整指南
后端
卷无止境13 小时前
FastAPI Guard 全解析,从概念到工程落地的实战指南
后端·python
卷无止境13 小时前
FastAPI Users 全面解析:概念、原理与工程实战
后端·python
程序员爱钓鱼13 小时前
Go switch 详解
后端·面试·go
程序员爱钓鱼13 小时前
Rust Struct结构体详解:定义自己的复杂数据类型
后端·面试·rust