一.生产者重试机制
1.原理
在生产者向消费者发送消息时,可能因网络波动,服务器内MQ崩溃导致发送失败.而重试机制会在失败后,自动重试,避免丢失消息.
2.示例
我们通过在application.yml里写入配置,来实现这个功能
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
# 重试配置
retry:
rabbitmq:
producer:
enabled: true # 开启重试
max-attempts: 3 # 最大重试次数(包含初始发送的那一次,共3次)
initial-interval: 1000 # 初始重试间隔(毫秒)
multiplier: 2 # 间隔乘数(下次间隔=当前间隔×乘数,如1s→2s→4s)
max-interval: 5000 # 最大重试间隔(避免间隔无限增大)
二.生产者确认机制
1.原理
生产者发送消息后,Broker 会通过 “确认信号” 告知生产者 “消息是否已成功接收并持久化”。只有收到 Broker 的确认信号,生产者才认为消息发送成功。
2.示例
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
# 生产者确认机制配置
publisher-confirm-type: correlated # 开启publisher confirm机制,并设置confirm类型
publisher-returns: true # 开启“消息返回”(配合确认机制,处理“消息到达Broker但路由失败”场景)
@Configuration
public class MqConfig {
private final RabbitTemplate rabbitTemplate;
@PostConstruct
public void init(){
rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
@Override
public void returnedMessage(ReturnedMessage returned) {
log.error("触发return callback,");
log.debug("exchange: {}", returned.getExchange());
log.debug("routingKey: {}", returned.getRoutingKey());
log.debug("message: {}", returned.getMessage());
log.debug("replyCode: {}", returned.getReplyCode());
log.debug("replyText: {}", returned.getReplyText());
}
});
}
}
他有两种方式,即简单方式和批量方式,对应配置中的SIMPLE和BATCH.
1.简单确认
每发送一条消息,就阻塞等待 Broker 的确认信号,同步获取结果,不过这样阻塞会降低发送效率,适合低并发场景.
2.批量确认
生产者批量发送多条消息后,一次性等待 Broker 对批量消息的确认信号,效率高,但若批量中某条消息失败,需自行定位失败消息,适合高并发场景.
三.发送失败处理机制
1.原理
当生产者重试耗尽后,或 Broker 拒绝接收消息(队列不存在或者没有权限时),需要此机制将信息存入
2.示例
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
# 业务队列与死信队列绑定配置
rabbitmq:
queues:
# 业务队列(发送失败的消息会转发到死信队列)
business-queue:
name: business.queue
durable: true # 持久化
arguments:
x-dead-letter-exchange: dlq.exchange # 绑定死信交换机
x-dead-letter-routing-key: dlq.routing.key # 死信路由键
# 死信队列(存储发送失败的消息)
dlq-queue:
name: dlq.queue
durable: true
exchanges:
# 死信交换机
dlq-exchange:
name: dlq.exchange
type: direct # 直连交换机
durable: true
bindings:
# 死信交换机与死信队列绑定
dlq-binding:
exchange: dlq.exchange
routing-key: dlq.routing.key
queue: dlq.queue
四、消息持久化机制
1. 原理
默认情况下,Broker 重启后消息会丢失(内存存储)。持久化机制通过将 “交换机、队列、消息” 三要素写入磁盘,确保 Broker 重启后消息不丢失。
核心条件(三者缺一不可):
1. 交换机持久化:durable: true(重启后交换机不删除);
2. 队列持久化:durable: true(重启后队列不删除);
3. 消息持久化:delivery-mode: 2(消息标记为持久化,写入磁盘)。
2.示例
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
# 消息持久化配置(交换机、队列、消息)
rabbitmq:
exchanges:
business-exchange:
name: business.exchange
type: direct
durable: true # 交换机持久化
queues:
business-queue:
name: business.queue
durable: true # 队列持久化
exclusive: false # 不排他(多消费者可访问)
auto-delete: false # 不自动删除(队列无连接时不删除)
bindings:
business-binding:
exchange: business.exchange
routing-key: business.routing.key
queue: business.queue
# 消息默认持久化(delivery-mode: 2)
template:
message-converter: org.springframework.amqp.support.converter.Jackson2JsonMessageConverter
exchange: business.exchange
routing-key: business.routing.key
delivery-mode: PERSISTENT # 等价于delivery-mode: 2
五、消费者确认机制(Consumer ACK)
1. 原理
消费者从 Broker 获取消息后,需向 Broker 发送 “确认信号(ACK)”,告知 Broker “消息是否已成功处理”。Broker 根据 ACK 类型决定消息后续处理:
- 自动 ACK(AUTO):消费者接收到消息后,立即自动发送 ACK(无论处理成功与否);
- 手动 ACK(MANUAL):消费者处理完消息后,手动调用 API 发送 ACK(处理成功发 ACK,失败发 NACK);
- 无 ACK(NONE):不发送 ACK,Broker 会一直保留消息,直到消费者连接断开。
2.示例
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
# 消费者确认机制配置
rabbitmq:
listener:
simple:
acknowledge-mode: MANUAL # 手动ACK模式(AUTO/NONE/MANUAL)
concurrency: 2 # 消费者最小并发数
max-concurrency: 5 # 消费者最大并发数
prefetch: 1 # 每次从Broker拉取1条消息(处理完再拉取下一条,避免消息堆积)
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class ConsumerAckHandler {
@RabbitListener(queues = "business.queue")
public void handleMessage(String messageContent, Channel channel, Message message) throws Exception {
try {
// 1. 处理业务逻辑(如订单支付、数据入库)
System.out.println("处理消息:" + messageContent);
// 2. 处理成功:手动发送ACK(multiple=false表示只确认当前消息)
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
// 3. 处理失败:发送NACK(requeue=false表示不重新入队,避免死循环)
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
System.err.println("消息处理失败,原因:" + e.getMessage());
}
}
}
六、消费失败重试机制
1. 原理
消费者处理消息时,可能因 “业务异常”(如数据库临时不可用、参数错误)导致处理失败。消费失败重试机制会在处理失败后,按照预设策略重试,避免因瞬时业务问题导致消息丢弃。
与 “生产者重试” 的区别:前者是 “发送阶段重试”,后者是 “消费阶段重试”;且消费重试通常需结合 “死信队列”,避免重试耗尽后消息丢失。
2.示例
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
# 消费失败重试配置
rabbitmq:
listener:
simple:
acknowledge-mode: MANUAL # 手动ACK(需配合重试逻辑)
retry:
enabled: true # 开启消费重试
max-attempts: 3 # 最大重试次数(1次初始消费+3次重试,共4次)
initial-interval: 2000 # 初始重试间隔(2秒)
multiplier: 1.5 # 间隔乘数(2s→3s→4.5s)
max-interval: 10000 # 最大重试间隔(10秒)
# 重试耗尽后转发到死信队列
default-requeue-rejected: false # 重试失败后不重新入队(触发死信)