一、RabbitMQ 核心原理
1.1 什么是RabbitMQ
RabbitMQ是一个开源的**消息代理(Message Broker)**软件,实现了高级消息队列协议(AMQP, Advanced Message Queuing Protocol)。它最初由Rabbit Technologies Ltd开发,现由VMware旗下的Pivotal Software维护。
1.2 核心架构组件

核心组件详解
| 组件 | 作用 | 特点 |
|---|---|---|
| Producer | 消息生产者,负责创建并发送消息 | 不直接将消息发送到队列,而是发送到Exchange |
| Exchange | 交换机,接收生产者发送的消息并根据路由规则转发到队列 | 有四种类型:direct、fanout、topic、headers |
| Queue | 消息队列,存储消息的缓冲区 | 具有持久化、排他性、自动删除等属性 |
| Consumer | 消息消费者,从队列中获取并处理消息 | 支持推(push)和拉(pull)两种模式 |
| Binding | 绑定,Exchange和Queue之间的关联规则 | 通过Routing Key建立关系 |
1.3 四种交换机类型
1. Direct Exchange(直连交换机)
- 路由规则:精确匹配Routing Key
- 使用场景:点对点消息传递
- 示例 :Routing Key为
order.create的消息只会路由到绑定Key为order.create的队列
2. Fanout Exchange(扇形交换机)
- 路由规则:广播到所有绑定队列,忽略Routing Key
- 使用场景:消息广播、群发通知
- 示例:系统公告同时推送给所有在线用户
3. Topic Exchange(主题交换机)
-
路由规则 :模式匹配Routing Key(支持
*和#通配符)-
*:匹配一个单词 -
#:匹配零个或多个单词
-
-
使用场景:复杂的路由场景、日志分类
-
示例:
-
Routing Key:
order.create.success -
匹配模式:
order.*.success✓、order.#✓
-
4. Headers Exchange(头交换机)
- 路由规则:根据消息Headers属性匹配
- 使用场景:多条件复杂路由
- 特点:性能略低于其他类型,使用较少
1.4 消息流转机制
消息生命周期:
1. Producer创建消息 → 设置属性(持久化、优先级、过期时间等)
2. 消息发送到Exchange
3. Exchange根据类型和Routing Key路由到Queue
4. Queue存储消息(内存/磁盘)
5. Consumer订阅Queue并消费消息
6. 根据ACK机制确认消息处理结果
7. 确认后消息从Queue删除,否则重新入队或进入死信队列
1.5 高级特性
消息确认机制(ACK)
- 自动确认(Auto ACK):消息发送后立即确认,速度快但可能丢消息
- 手动确认(Manual ACK):业务处理完成后手动发送确认,可靠性高
消息持久化
// 队列持久化
channel.queueDeclare("queue_name", true, false, false, null);
// 消息持久化
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
.deliveryMode(2) // 1=非持久化, 2=持久化
.build();
channel.basicPublish("", "queue_name", props, message.getBytes());
死信队列(DLX, Dead Letter Exchange)
消息成为死信的三种情况:
- 消息被拒绝(
basic.reject/basic.nack)且requeue=false - 消息过期(TTL)
- 队列达到最大长度
延迟队列
通过TTL + 死信队列实现延迟消息:
消息 → 延迟队列(设置TTL,不设置消费者)→ 过期后 → 死信交换机 → 目标队列 → 消费者
二、适用场景
2.1 典型应用场景
| 场景 | 说明 | 优势 |
|---|---|---|
| 异步处理 | 用户注册后发送邮件/短信 | 降低响应时间,提升用户体验 |
| 应用解耦 | 订单系统与库存系统分离 | 系统独立演进,降低维护成本 |
| 流量削峰 | 秒杀活动请求缓冲 | 保护后端系统,防止过载崩溃 |
| 日志处理 | 分布式系统日志收集 | 集中处理,便于分析 |
| 任务调度 | 定时任务、延迟任务 | 精确控制执行时间 |
| 广播通知 | 配置变更推送 | 实时同步多实例 |
2.2 场景对比:同步 vs 异步
同步调用(不推荐):
用户请求 → 订单服务 → 库存服务 → 支付服务 → 物流服务 → 响应用户
总耗时 = 各服务耗时之和(可能数秒)
异步调用(推荐):
用户请求 → 订单服务 → 发送MQ → 立即响应用户(<100ms)
↓
库存服务/支付服务/物流服务(并行处理)
2.3 选型对比
| 特性 | RabbitMQ | Kafka | RocketMQ |
|---|---|---|---|
| 开发语言 | Erlang | Scala/Java | Java |
| 消息模型 | 传统队列,支持多种模式 | 发布订阅,分区日志 | 传统队列 + 发布订阅 |
| 吞吐量 | 万级/秒 | 百万级/秒 | 十万级/秒 |
| 延迟 | 微秒级 | 毫秒级 | 毫秒级 |
| 可靠性 | 高(支持事务) | 高 | 极高(金融级) |
| 功能丰富度 | 极高(路由灵活) | 较低 | 高(支持事务消息) |
| 适用场景 | 复杂路由、企业应用 | 大数据日志、流处理 | 金融交易、电商 |
三、Spring Boot 与 RabbitMQ 版本兼容性
版本对应关系
| Spring Boot 版本 | Spring AMQP 版本 | amqp-client 版本 | 兼容 RabbitMQ 版本 | JDK 要求 |
|---|---|---|---|---|
| 3.4.x | 3.2.x | 5.22.x | 3.13.x, 4.0.x - 4.2.x | JDK 17+ |
| 3.3.x | 3.1.x | 5.21.x | 3.12.x - 4.0.x | JDK 17+ |
| 3.2.x | 3.1.x | 5.19.x | 3.12.x - 4.0.x | JDK 17+ |
| 2.7.x | 2.4.x | 5.16.x | 3.8.x - 3.12.x | JDK 8+ |
注意 :Spring Boot 3.x 要求 JDK 17 或更高版本
四、Spring Boot 集成实战(基于 RabbitMQ 4.2.x + Spring Boot 3.4.x)
版本说明 :本文实战基于 RabbitMQ 4.2.5 (当前最新稳定版,2026-03-21发布)与 Spring Boot 3.4.x 版本组合。RabbitMQ 4.x 系列是目前的活跃开发主线,相比 3.13.x 提供了 Khepri 元数据存储、SQL 流过滤等新特性
4.1 环境准备
系统要求
- JDK: 17 或更高版本(Spring Boot 3.x 强制要求)
- RabbitMQ Server: 4.2.x(推荐)或 3.13.x(维护中)
- Spring Boot: 3.2.x / 3.3.x / 3.4.x
Maven依赖
<dependencies>
<!-- Spring Boot AMQP Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- 可选:监控和管理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
application.yml配置
spring:
rabbitmq:
host: localhost
port: 5672
username: admin
password: admin
virtual-host: /
# 连接池配置
listener:
simple:
# 并发消费者数量
concurrency: 5
max-concurrency: 20
# 手动确认模式
acknowledge-mode: manual
# 每次从队列获取的消息数
prefetch: 10
# 失败重试
retry:
enabled: true
initial-interval: 1000ms
max-attempts: 3
max-interval: 10000ms
multiplier: 2
# 生产者确认
publisher-confirm-type: correlated
publisher-returns: true
# 连接超时
connection-timeout: 15000
# 心跳
requested-heartbeat: 30
4.2 基础配置类
@Configuration
public class RabbitConfig {
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
// 强制消息必须路由到队列,否则触发ReturnCallback
template.setMandatory(true);
// 消息发送到Exchange的回调
template.setConfirmCallback((correlationData, ack, cause) -> {
if (ack) {
System.out.println("消息成功发送到Exchange: " + correlationData);
} else {
System.err.println("消息发送到Exchange失败: " + cause);
}
});
// 消息无法路由到Queue的回调
template.setReturnsCallback(returned -> {
System.err.println("消息路由失败: " + returned.getMessage() +
", 原因: " + returned.getReplyText());
});
return template;
}
// ==================== Direct Exchange 配置 ====================
@Bean
public DirectExchange orderExchange() {
return new DirectExchange("order.exchange", true, false);
}
@Bean
public Queue orderQueue() {
return QueueBuilder.durable("order.queue")
// 死信交换机配置
.withArgument("x-dead-letter-exchange", "order.dlx.exchange")
.withArgument("x-dead-letter-routing-key", "order.dlx.routing")
// 队列TTL(消息在队列中存活时间)
.withArgument("x-message-ttl", 30000)
// 队列最大长度
.withArgument("x-max-length", 10000)
.build();
}
@Bean
public Binding orderBinding() {
return BindingBuilder.bind(orderQueue())
.to(orderExchange())
.with("order.routing.key");
}
// ==================== Topic Exchange 配置 ====================
@Bean
public TopicExchange logExchange() {
return new TopicExchange("log.exchange", true, false);
}
@Bean
public Queue errorLogQueue() {
return new Queue("log.error.queue", true);
}
@Bean
public Queue infoLogQueue() {
return new Queue("log.info.queue", true);
}
@Bean
public Binding errorLogBinding() {
// 只接收error级别的日志
return BindingBuilder.bind(errorLogQueue())
.to(logExchange())
.with("log.error.*");
}
@Bean
public Binding infoLogBinding() {
// 接收info和warning级别的日志
return BindingBuilder.bind(infoLogQueue())
.to(logExchange())
.with("log.info.*");
}
// ==================== 死信队列配置 ====================
@Bean
public DirectExchange dlxExchange() {
return new DirectExchange("order.dlx.exchange", true, false);
}
@Bean
public Queue dlxQueue() {
return new Queue("order.dlx.queue", true);
}
@Bean
public Binding dlxBinding() {
return BindingBuilder.bind(dlxQueue())
.to(dlxExchange())
.with("order.dlx.routing");
}
// ==================== 延迟队列配置(TTL + DLX) ====================
@Bean
public Queue delayQueue() {
return QueueBuilder.durable("delay.queue")
.withArgument("x-dead-letter-exchange", "order.exchange")
.withArgument("x-dead-letter-routing-key", "order.routing.key")
.withArgument("x-message-ttl", 60000) // 60秒延迟
.build();
}
}
4.3 生产者代码
import jakarta.annotation.Resource;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class MessageProducer {
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* 发送普通消息
*/
public void sendOrderMessage(Order order) {
// 创建关联数据,用于确认回调
CorrelationData correlationData = new CorrelationData(order.getOrderId());
rabbitTemplate.convertAndSend(
"order.exchange", // 交换机
"order.routing.key", // 路由键
order, // 消息体
message -> { // 消息属性配置
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
message.getMessageProperties().setContentType("application/json");
message.getMessageProperties().setPriority(5); // 优先级
return message;
},
correlationData // 关联数据
);
}
/**
* 发送延迟消息
*/
public void sendDelayMessage(Order order, int delayMillis) {
rabbitTemplate.convertAndSend(
"order.exchange",
"order.routing.key",
order,
message -> {
// 设置消息级别的TTL(优先级高于队列TTL)
message.getMessageProperties().setExpiration(String.valueOf(delayMillis));
return message;
}
);
}
/**
* 发送Topic消息
*/
public void sendLogMessage(String level, String content) {
String routingKey = "log." + level + ".app";
rabbitTemplate.convertAndSend("log.exchange", routingKey, content);
}
/**
* 批量发送(高性能场景)
*/
public void batchSend(List<Order> orders) {
rabbitTemplate.invoke(operations -> {
orders.forEach(order -> {
operations.convertAndSend("order.exchange", "order.routing.key", order);
});
return null;
}, (tag, multiple) -> {
// 确认回调
}, (tag, multiple) -> {
// 失败回调
});
}
}
4.4 消费者代码
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class MessageConsumer {
/**
* 普通消费 - 自动确认
*/
@RabbitListener(queues = "order.queue")
public void handleOrder(Order order) {
log.info("收到订单消息: {}", order);
// 业务处理
//processOrder(order);
}
/**
* 手动确认模式 - 推荐生产使用
*/
@RabbitListener(queues = "order.queue", ackMode = "MANUAL")
public void handleOrderManual(Order order, Message message, Channel channel) throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
log.info("手动确认模式收到订单: {}", order);
//processOrder(order);
// 确认消息(multiple=false只确认当前消息)
channel.basicAck(deliveryTag, false);
} catch (Exception e) {
log.error("处理消息失败: {}", e.getMessage());
// 拒绝消息并重新入队(根据重试次数决定是否入队)
if (message.getMessageProperties().getRedelivered()) {
// 已经是二次投递,不再入队,进入死信队列
channel.basicReject(deliveryTag, false);
} else {
// 首次失败,重新入队重试
channel.basicNack(deliveryTag, false, true);
}
}
}
/**
* Topic消费者 - 只接收错误日志
*/
@RabbitListener(queues = "log.error.queue")
public void handleErrorLog(String logContent) {
log.error("收到错误日志: {}", logContent);
// 发送告警通知
//sendAlert(logContent);
}
/**
* 死信队列消费者
*/
@RabbitListener(queues = "order.dlx.queue")
public void handleDeadLetter(Message message, Channel channel) throws IOException {
log.warn("收到死信消息: {}", new String(message.getBody()));
// 记录到数据库或发送告警
//saveDeadLetter(message);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
/**
* 并发消费配置
*/
@RabbitListener(queues = "order.queue", containerFactory = "customContainerFactory")
public void handleConcurrent(Order order) {
log.info("线程[{}]处理订单: {}", Thread.currentThread().getName(), order.getOrderId());
//processOrder(order);
}
@Bean
public SimpleRabbitListenerContainerFactory customContainerFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer,
ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setConcurrentConsumers(10); // 初始并发数
factory.setMaxConcurrentConsumers(20); // 最大并发数
factory.setPrefetchCount(50); // 每次预取50条
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
return factory;
}
}
4.5 完整案例:订单系统
场景描述
电商订单流程:创建订单 → 扣减库存 → 支付 → 发货 → 完成
实现代码
// ============ 实体类 ============
@Data
public class OrderEvent implements Serializable {
private String orderId;
private String userId;
private BigDecimal amount;
private List<OrderItem> items;
private OrderStatus status;
private LocalDateTime createTime;
}
// ============ 订单服务 ============
@Service
public class OrderService {
@Autowired
private MessageProducer producer;
@Autowired
private OrderRepository orderRepository;
@Transactional
public Order createOrder(CreateOrderRequest request) {
// 1. 创建订单
Order order = new Order();
order.setOrderId(generateOrderId());
order.setStatus(OrderStatus.CREATED);
orderRepository.save(order);
// 2. 发送订单创建事件(异步处理库存)
OrderEvent event = convertToEvent(order);
producer.sendOrderMessage(event);
// 3. 发送延迟消息(15分钟未支付自动取消)
producer.sendDelayMessage(event, 15 * 60 * 1000);
return order;
}
}
// ============ 库存服务消费者 ============
@Component
public class InventoryConsumer {
@Autowired
private InventoryService inventoryService;
@RabbitListener(queues = "inventory.queue")
public void handleInventoryDeduct(OrderEvent event, Channel channel, Message message)
throws IOException {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
// 幂等性检查
if (inventoryService.isProcessed(event.getOrderId())) {
channel.basicAck(deliveryTag, false);
return;
}
// 扣减库存
inventoryService.deduct(event.getItems());
// 发送库存扣减成功事件
event.setStatus(OrderStatus.INVENTORY_DEDUCTED);
producer.sendEvent("payment.exchange", event);
channel.basicAck(deliveryTag, false);
} catch (InsufficientInventoryException e) {
// 库存不足,不重新入队,进入死信队列处理
log.error("库存不足: {}", e.getMessage());
channel.basicReject(deliveryTag, false);
// 发送订单取消通知
producer.sendOrderCancel(event.getOrderId(), "库存不足");
} catch (Exception e) {
log.error("库存扣减失败: {}", e.getMessage());
channel.basicNack(deliveryTag, false, true);
}
}
}
// ============ 支付超时检查 ============
@Component
public class PaymentTimeoutConsumer {
@RabbitListener(queues = "payment.timeout.queue")
public void handleTimeout(OrderEvent event) {
// 检查订单状态
Order order = orderService.getOrder(event.getOrderId());
if (order.getStatus() == OrderStatus.CREATED) {
// 未支付,取消订单
orderService.cancelOrder(event.getOrderId(), "支付超时");
// 回滚库存
inventoryService.rollback(event.getItems());
log.info("订单[{}]因支付超时已自动取消", event.getOrderId());
}
}
}
五、常见问题与排错指南
5.1 消息丢失问题
问题场景
- 生产者发送消息成功,但消费者未收到
- 消费者处理成功,但消息未从队列删除
- RabbitMQ重启后消息丢失
解决方案
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ReliableConfig {
/**
* 1. 生产者确认配置
*/
@Bean
public RabbitTemplate reliableRabbitTemplate(ConnectionFactory factory) {
RabbitTemplate template = new RabbitTemplate(factory);
// 开启Confirm模式
template.setConfirmCallback((correlationData, ack, cause) -> {
if (!ack) {
// 记录失败日志,后续补偿发送
log.error("消息发送失败: {}", cause);
saveFailedMessage(correlationData);
}
});
// 开启Return模式(消息无法路由时触发)
template.setReturnsCallback(returned -> {
log.error("消息路由失败: exchange={}, routingKey={}",
returned.getExchange(), returned.getRoutingKey());
});
return template;
}
/**
* 2. 消费者手动ACK配置
*/
@Bean
public SimpleRabbitListenerContainerFactory reliableFactory(ConnectionFactory factory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(factory);
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
factory.setPrefetchCount(1); // 每次只取1条,处理完再取下一条
return factory;
}
}
# 3. 队列和消息持久化配置
spring:
rabbitmq:
# 生产者确认
publisher-confirm-type: correlated
publisher-returns: true
template:
mandatory: true # 强制消息必须路由
5.2 重复消费问题
问题原因
- 消费者处理成功但ACK失败,消息重新入队
- 网络抖动导致重复投递
- 消费者异常退出,消息被其他消费者获取
幂等性解决方案
import com.rabbitmq.client.Channel;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class IdempotentConsumer {
@Resource
private StringRedisTemplate redisTemplate;
private static final String IDEMPOTENT_KEY_PREFIX = "mq:consumer:";
private static final long EXPIRE_TIME = 24 * 60 * 60; // 24小时
@RabbitListener(queues = "order.queue")
public void consume(Message message, Channel channel) throws IOException {
String messageId = message.getMessageProperties().getMessageId();
String uniqueKey = IDEMPOTENT_KEY_PREFIX + messageId;
// 1. 幂等性检查(Redis原子操作)
Boolean isNew = redisTemplate.opsForValue()
.setIfAbsent(uniqueKey, "1", EXPIRE_TIME, TimeUnit.SECONDS);
if (Boolean.FALSE.equals(isNew)) {
log.warn("消息[{}]已处理,跳过", messageId);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
return;
}
try {
// 2. 业务处理
//processBusiness(message);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
// 3. 处理失败,删除幂等标记,允许重试
redisTemplate.delete(uniqueKey);
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
}
}
// 数据库唯一索引方案(备用)
public void processWithDBIdempotent(OrderEvent event) {
try {
// 插入消费记录(唯一索引:message_id)
messageRecordDao.insert(new MessageRecord(event.getMessageId()));
// 执行业务
processOrder(event);
} catch (DuplicateKeyException e) {
log.warn("重复消息,已跳过: {}", event.getMessageId());
}
}
}
5.3 消息积压问题
现象
- 队列消息数持续增长
- 消费者Lag值居高不下
- 内存/磁盘告警
排查步骤
# 1. 查看队列状态
rabbitmqctl list_queues name messages_ready messages_unacknowledged
# 2. 查看消费者状态
rabbitmqctl list_consumers
# 3. 查看连接和通道
rabbitmqctl list_connections peer_host peer_port state
rabbitmqctl list_channels connection pid consumer_count
解决方案
/**
* 紧急扩容:增加消费者实例
*/
@Component
public class ScaleOutConsumer {
@RabbitListener(queues = "order.queue", containerFactory = "scaleFactory")
public void consume(Message message) {
// 简化处理逻辑,只保留核心操作
quickProcess(message);
}
@Bean
public SimpleRabbitListenerContainerFactory scaleFactory(ConnectionFactory factory) {
SimpleRabbitListenerContainerFactory f = new SimpleRabbitListenerContainerFactory();
f.setConnectionFactory(factory);
f.setConcurrentConsumers(50); // 紧急扩容到50个消费者
f.setMaxConcurrentConsumers(100);
f.setPrefetchCount(500); // 批量预取
f.setBatchSize(100); // 批量处理
return f;
}
}
/**
* 降级方案:丢弃非关键消息
*/
@Service
public class DegradeService {
public void discardNonCriticalMessages(String queueName) {
// 获取队列深度
int depth = getQueueDepth(queueName);
if (depth > 100000) {
// 超过10万,启动丢弃策略
rabbitAdmin.purgeQueue(queueName, false); // 清空队列(谨慎使用)
// 或者消费但不处理
// 记录日志后直接ACK
}
}
}
5.4 常见错误与解决
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
ACCESS_REFUSED |
权限不足 | 检查用户权限:rabbitmqctl set_permissions -p / user ".*" ".*" ".*" |
NOT_FOUND - no exchange |
交换机不存在 | 先声明交换机,或检查名称拼写 |
PRECONDITION_FAILED |
队列参数不匹配 | 删除旧队列重建,或使用不同名称 |
CHANNEL_ERROR - expected 'channel.open' |
通道状态异常 | 检查连接是否被意外关闭 |
CONNECTION_FORCED |
连接被强制关闭 | 检查心跳设置,网络稳定性 |
RESOURCE_LOCKED |
队列被其他连接独占 | 检查排他性设置,或等待其他连接释放 |
5.5 监控与告警配置
# Spring Boot Actuator监控
management:
endpoints:
web:
exposure:
include: health,metrics,prometheus
endpoint:
health:
show-details: always
# 自定义健康检查
@Component
public class RabbitHealthIndicator implements HealthIndicator {
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public Health health() {
try {
rabbitTemplate.execute(channel -> {
channel.queueDeclarePassive("health.check");
return null;
});
return Health.up()
.withDetail("message", "RabbitMQ连接正常")
.build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
}
六、最佳实践总结
6.1 设计原则
- 消息大小:单条消息建议不超过1MB,大数据使用对象存储+消息通知
- 队列数量:避免过多队列(<1000),使用Topic模式减少队列数
- TTL设置:合理设置过期时间,避免消息无限堆积
- 命名规范 :使用
业务.功能.类型格式,如order.create.queue
6.2 配置清单
spring:
rabbitmq:
# 连接配置
host: ${RABBITMQ_HOST:localhost}
port: ${RABBITMQ_PORT:5672}
username: ${RABBITMQ_USER:admin}
password: ${RABBITMQ_PASS:admin}
virtual-host: ${RABBITMQ_VHOST:/}
# 可靠性配置
publisher-confirm-type: correlated
publisher-returns: true
template:
mandatory: true
retry:
enabled: true
initial-interval: 1000ms
max-attempts: 3
# 消费配置
listener:
simple:
acknowledge-mode: manual
prefetch: 10
concurrency: 5
max-concurrency: 20
default-requeue-rejected: false # 失败不入队,进入死信
retry:
enabled: true
stateless: true
initial-interval: 1000ms
multiplier: 2
max-attempts: 3
max-interval: 10000ms
6.3 性能优化建议
| 优化项 | 配置 | 效果 |
|---|---|---|
| 批量发送 | template.invoke() |
减少网络往返 |
| 批量消费 | setBatchSize() |
提高吞吐量 |
| 适当Prefetch | 根据处理速度调整 | 平衡吞吐和内存 |
| 并发消费 | concurrency |
提升并行度 |
| 禁用不必要特性 | 非持久化、自动删除 | 减少IO开销 |