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 防消费者处理失败丢消息。四者结合,消息可靠性基本稳了。

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
大勇前进3 天前
原生 PHP 还是 Laravel?小项目到底要不要上框架
后端
yuzhi_liu3 天前
我用 LangGraph4j 实现 Multi-Agent Supervisor
后端
alsmile3 天前
Node-RED 之外,国产规则引擎的新方案:基于标准语法,Go 先行实现
后端·开源·go
大白803 天前
PHP 内存溢出排查思路:看懂报错日志,精准定位问题
后端
二月龙3 天前
PHP 接口返回统一响应封装,让前后端对接更省心
后端
盖伦发发3 天前
软件工程SOLID 五大设计原则
后端·软件工程