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

相关推荐
jyOverQ4 小时前
RabbitMQ 消息积压怎么办?Prefetch、消费者并发与扩容
分布式·后端·rabbitmq
东风破_11 小时前
从跨域到 WebSocket:前端跨域方案、SSE 与双向实时通信详解
前端·后端
行百里er12 小时前
Gateway 上别硬塞 MVC:DeferredImportSelector 看菜下锅
spring boot·后端·开源
名字还没想好☜12 小时前
Java 遍历时删元素抛 ConcurrentModificationException:fail-fast 原理与三种正确删法
后端
IT_陈寒13 小时前
React Hooks闭包陷阱差点让我加班到凌晨
前端·人工智能·后端
码事漫谈14 小时前
本体论,彻底懂
后端
创新技术阁14 小时前
FastapiAdmin 系统日志体系与核心配置参数详解
前端·后端·fastapi
掘金者阿豪14 小时前
SQL Server 迁到金仓,真正麻烦的不是数据,而是这些 T-SQL
后端
Kyrie_kk14 小时前
Java--IO--Path文件访问
java·后端
wxwx_bscxy32215 小时前
基于springboot宠物领养系统的设计与实现
数据库·spring boot·后端·spring·宠物