一 生产者消息可靠性
保证 RabbitMQ 生产者可靠性的关键在于:通过自动重连机制
(如连接工厂配置心跳检测、失败自动恢复)确保网络异常时生产者能快速恢复连接,同时结合Publisher Confirm 确认机制
(异步回调 ConfirmCallback 实时反馈消息是否成功到达交换机),对确认失败的消息触发重试逻辑(如指数退避重试或存入补偿队列),最终形成"连接恢复-消息确认-失败重试"的闭环,避免因网络抖动或瞬时故障导致消息丢失。
二 生产者重连
1 介绍
生产者重连是指当消息生产者(如RabbitMQ客户端)因网络故障、服务重启或认证失败等导致与消息中间件(Broker)的连接断开时,自动触发重新建立连接并恢复消息发送的机制,其核心目的是通过容错设计避免因临时故障导致消息丢失,提升系统可靠性。
2 application.yaml -- publisher,加入生产者重试配置
java
spring:
rabbitmq:
host: 192.168.44.128
port: 5672
virtual-host: /midhuang
username: dahuang
password: "dahuang66"
# 生产者重试配置
connection-timeout: 1s # 连接超时时间
template:
retry:
enabled: true # 开启生产者重试
initial-interval: 1000ms # 初始重试间隔
multiplier: 1.0 # 等待时间倍数
max-attempts: 3 # 最大重试次数
logging:
level:
cn.tj.consumer.listeners: DEBUG # 设置为 DEBUG 以查看详细日志
3 发送阻塞消息
此时停掉MQ服务,再发送消息,消息发送失败时会进行3次重试,需注意此时的重试是连接失败的重试,而不是消息发送抛出异常的重试。抛出异常的话不会开启重试。
java
@SpringBootTest
class PublisherApplicationTests {
// 注入 RabbitTemplate
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void testSendObject() {
// 1. 创建测试消息(Map结构)
Map<String, Object> msg = new HashMap<>(2);
msg.put("name", "dahuang");
msg.put("age", 18);
// 2. 发送消息到指定队列(需确保 routingKey 与队列绑定)
rabbitTemplate.convertAndSend("object.queue", msg);
// 3. 可选:验证发送成功(通过日志或断言接收端消息)
System.out.println("Sent message: " + msg);
}
}
SpringAMQP的重试是阻塞式的重试,当前线程会被阻塞,因此rabbitTemplate.convertAndSend
之后的代码需要一直等待。 可以考虑使用异步线程来执行发送消息的代码。
三 生产者确认 -- 生产者消息可靠性
1 介绍
生产者确认机制通过PublisherConfirm
和PublisherReturn
两种机制实现,其核心目的是确保消息从生产者到Broker的可靠性传递。
场景描述 | PublisherConfirm | PublisherReturn | 最终状态 | 关键说明 |
---|---|---|---|---|
消息成功投递到交换机,且路由到队列(非持久化) | ✅ ACK | ❌ 不触发 | 投递成功 | 临时消息仅需到达队列即确认,不保证持久化。 |
消息成功投递到交换机,且路由到队列(持久化完成) | ✅ ACK | ❌ 不触发 | 投递成功 | 持久消息需等待磁盘写入完成才返回ACK,性能较低但可靠性更高。 |
消息到达交换机,但路由失败(如路由键错误、队列不存在) | ✅ ACK | ⚠️ 触发(返回错误) | 投递到交换机成功,但路由失败 | 需通过ReturnCallback 获取具体失败原因(如NO_ROUTE ),可结合重试或补偿逻辑。 |
消息未到达交换机(如网络中断、Broker不可用) | ❌ NACK | ❌ 不触发 | 投递失败 | 需结合重试机制或降级处理,避免消息丢失。 |
2 application.yaml -- publisher,加入生产者确认机制配置publisher-confirm-type
模式 | 类型 | 工作原理 | 性能影响 | 适用场景 | 注意事项 |
---|---|---|---|---|---|
none |
关闭确认 | 不启用任何确认机制,消息发送后立即返回,不关心是否成功到达 Broker。 | 无额外开销 | 对消息可靠性要求极低的场景(如日志记录、非关键通知)。 | 消息丢失风险高,需确保业务能容忍数据丢失。 |
simple |
同步阻塞确认 | 发送消息后,线程阻塞等待 Broker 返回确认结果(ACK/NACK),超时或失败抛出异常。 | 高延迟 | 对消息可靠性要求高,且能接受同步阻塞的场景(如金融交易、订单处理)。 | 1. 吞吐量低(每条消息需等待确认); 2. 超时时间需合理设置(避免长时间阻塞)。 |
correlated |
异步回调确认 | 发送消息后立即返回,通过回调接口(ConfirmCallback )异步接收确认结果。 |
最低性能损耗 | 高并发、对延迟敏感的场景(如实时通知、事件驱动架构)。 | 1. 需实现回调逻辑处理 ACK/NACK; 2. 结合重试机制处理 NACK 情况。 |
java
spring:
rabbitmq:
host: 192.168.44.128
port: 5672
virtual-host: /midhuang
username: dahuang
password: "dahuang66"
connection-timeout: 1s # 连接超时时间
# 生产者确认机制配置
publisher-confirm-type: correlated # 异步回调确认模式
publisher-returns: true # 开启Return机制(捕获路由失败)
template:
mandatory: true # 强制触发ReturnCallback
# 生产者重试配置(针对网络波动等临时性失败)
retry:
enabled: true # 开启重试
initial-interval: 1000ms # 首次重试间隔(1秒)
multiplier: 1.0 # 后续重试间隔倍数(1.0表示固定间隔)
max-attempts: 3 # 最大重试次数(实际重试次数=max-attempts-1)
logging:
level:
cn.tj.consumer.listeners: DEBUG # 设置为 DEBUG 以查看详细日志
3 MqConfirmConfig -- 编写回调函数
每个RabbitTemplate只能配置一个ReturnCallback
,因此需要在项目启动过程中配置。在 Spring AMQP 中,ReturnCallback 是必需的,因为当消息因路由键不匹配或队列不存在而无法到达队列时,RabbitMQ 默认会静默丢弃消息;
通过配置mandatory: true
和publisher-returns: true
后,ReturnCallback
能捕获这些路由失败事件,避免消息丢失,同时允许开发者实现补偿逻辑(如日志记录或重试),且由于 RabbitTemplate 是单例的,回调需在项目启动时统一配置以保证唯一性。
java
// ApplicationContextAware 是 Spring 提供的接口,实现它能让 Bean 在初始化时
// 通过 setApplicationContext() 方法获取 Spring 容器的引用,
// 从而动态访问其他 Bean(如代码中通过容器获取 RabbitTemplate)或操作容器功能
// 避免硬编码依赖,实现解耦。
@Slf4j
@Configuration
public class MqConfirmConfig implements ApplicationContextAware {
// ApplicationContext 是 Spring 框架的核心容器接口,负责管理 Bean 的生命周期、配置依赖注入、提供环境上下文及访问应用资源,本质是所有 Spring 组件的中央注册表和运行时环境。
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
// 配置 ReturnsCallback(处理路由失败)
rabbitTemplate.setReturnsCallback(returned -> {
log.error("消息路由失败!交换机: {}, 路由键: {}, 消息: {}, 错误码: {}, 原因: {}",
returned.getExchange(),
returned.getRoutingKey(),
new String(returned.getMessage().getBody()),
returned.getReplyCode(),
returned.getReplyText());
});
}
}
4 发送消息 -- PublisherApplicationTests
ConfirmCallback
是 Spring AMQP 的异步回调接口,用于确认 RabbitMQ 消息是否成功到达交换机(ack 标识结果),需配合 publisher-confirm-type: correlated 配置,常与ReturnCallback
联用保障消息发送可靠性。
java
@Slf4j
@SpringBootTest
class PublisherApplicationTests {
// 注入 RabbitTemplate
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void testConfirmCallback() throws InterruptedException {
// 1. 创建唯一消息标识(用于跟踪消息确认状态)
CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());
// 2. 注册回调:处理消息确认结果(成功/失败)
cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
@Override
public void onFailure(Throwable ex) {
// 2.1 回调异常时触发(如网络中断)
log.error("消息回调失败", ex);
}
@Override
public void onSuccess(CorrelationData.Confirm result) {
// 2.2 收到RabbitMQ确认回执时触发
log.debug("收到 ConfirmCallback 回执");
if (result.isAck()) {
// 2.3 消息成功到达交换机
log.debug("消息发送成功,收到 ACK");
} else {
// 2.4 消息被交换机拒绝(如交换机不存在)
log.error("消息发送失败,收到 NACK,原因: {}", result.getReason());
}
}
});
// 3. 发送消息到指定交换机和路由键(附带消息标识)
rabbitTemplate.convertAndSend("dahuang.dircet", "yellow", "你的消息", cd);
// 4. 休眠2秒接收回执,因为 RabbitMQ 的确认回调是异步的,
// 不加 Thread.sleep(2000) 可能导致测试线程提前结束,未捕获到 ACK/NACK 回调结果。
Thread.sleep(2000);
}
}

5 发送错误消息
① 错误的交换机
java
rabbitTemplate.convertAndSend("uang.direct", "yellow", "你的消息", cd);

② 错误的key
java
rabbitTemplate.convertAndSend("huang.direct", "blue", "你的消息", cd);
