RabbitMQ | RocketMQ | Kafka 基础选型
一、三款 MQ 本质差异(先建立认知)
| 维度 | RabbitMQ | RocketMQ | Kafka |
|---|---|---|---|
| 出身 | AMQP,Erlang | 阿里,Java | LinkedIn,Scala/Java |
| 吞吐量 | 万级 ~ 数万 | 十万 ~ 百万 | 百万 ~ 千万 |
| 延迟 | 最低(ms 级) | 很低 | 低(但批次攒数据) |
| 消息模型 | Exchange + Queue | Topic + Tag + Queue | Topic + Partition |
| 顺序消息 | ❌(难) | ✅(单Queue) | ✅(Partition) |
| 延迟队列 | TTL+DLX / 插件 | ✅原生支持 | ❌不支持 |
| 事务消息 | ❌ | ✅ | ❌(新版有但弱) |
| 死信队列 | ✅ | ✅ | ❌(需自行实现) |
| 消费模式 | Push | Push/Pull | Pull |
| 运维复杂度 | 简单 | 中等 | 较复杂 |
| 典型用途 | 业务解耦 / 延迟 / RPC-like | 金融 / 订单 / 事务 | 日志 / 埋点 / 流计算 |
二、RabbitMQ(你正在学的 ✅)
✅ 适合
- 业务系统解耦
- 订单 → 库存 / 短信 / 积分
- 延迟队列(30 分钟关单 ✅)
- 请求少 / 实时性高
- 中小型 / 中大型单体或微服务
❌ 不适合
- 超高通量(日志、埋点)
- 海量堆积(TB 级)
- 流式计算
✅ 典型场景
下单 → 库存扣减
下单 → 发送短信
订单创建 → 30分钟未支付关单(TTL+DLX)
👉 你现在的项目首选 RabbitMQ
三、RocketMQ(阿里系 / 金融级)
✅ 适合
- 电商 / 金融 / 支付
- 需要:
- 顺序消息(同一订单顺序)
- 事务消息(本地事务 + MQ 最终一致)
- 延迟消息(18 个固定等级)
- 海量堆积
- Spring Cloud Alibaba 原生支持
❌ 不适合
- 日志采集(不如 Kafka 经济)
- 简单延迟队列(不如 RabbitMQ 灵活,只固定等级)
✅ 典型场景
支付成功 → 账户扣款(事务消息)
订单流水 → 按顺序落库
秒杀 → 削峰
四、Kafka(大数据 / 日志 / 流计算)
✅ 适合
- 日志收集(ELK)
- 用户行为埋点
- 指标采集
- 实时流计算(Flink / Spark Streaming)
- 超高吞吐 + 数据重放
❌ 不适合
- 业务延迟队列
- 死信处理
- 单条消息 ACK 精细控制
- 简单业务解耦(杀鸡用牛刀)
✅ 典型场景
Nginx / 应用日志 → Kafka → Logstash → ES
用户点击流 → Kafka → Flink → 实时大盘
五、选型对比速记表(面试背这个 ✅)
| 你要不要... | 选 |
|---|---|
| 业务解耦 + 延迟队列 + 简单运维 | RabbitMQ |
| 电商交易 + 事务消息 + 顺序消息 | RocketMQ |
| 日志 / 流数据 / 超高吞吐 | Kafka |
六、真实公司常见搭配(你以后会看到)
RabbitMQ → 核心业务(订单 / 支付 / 通知)
RocketMQ → 交易核心 / 分布式事务(阿里系)
Kafka → 日志 / 埋点 / 实时分析
✅ 不是三选一,经常三者共存
七、结合你当前阶段的建议 ✅
你现在是:
- ✅ 学 Spring Cloud Alibaba
- ✅ 做订单 / 支付 / 关单
- ✅ 需要延迟队列 + DLQ + 易部署
👉 RabbitMQ 是你现在最合理选择
RocketMQ / Kafka 了解即可,先不急着深入,除非:
- 公司已用 RocketMQ
- 或准备做日志 / 大数据方向
八、一句话总结 ✅
RabbitMQ = 业务解耦 + 延迟队列(你当前必学)
RocketMQ = 电商交易 + 事务消息 + 顺序消息
Kafka = 日志 + 流计算 + 超高吞吐
中大型系统常三者并存,各司其职
一、RabbitMQ 整体架构与原理
RabbitMQ 是实现 AMQP 0-9-1 协议 的开源消息代理(Message Broker),核心思想是:生产者不直接发消息给队列,而是发给交换机,由交换机按规则路由到队列。
核心组件
| 组件 | 说明 |
|---|---|
| Broker | RabbitMQ 服务节点,负责接收、存储、转发消息 |
| Producer(Publisher) | 消息生产者,发送消息到 Exchange |
| Consumer | 消息消费者,从 Queue 拉取或被动接收推送消息 |
| Exchange(交换机) | 路由中枢,不存储消息,按类型+Binding规则决定消息去哪个Queue |
| Queue(队列) | 真正存储消息的地方,支持持久化、TTL、长度限制 |
| Binding(绑定) | Exchange ↔ Queue 的关联关系,附带 Binding Key(路由匹配依据) |
| Routing Key | 生产者发消息时携带的字符串,Exchange 用它做路由判断 |
| Virtual Host(vhost) | 逻辑隔离空间,各 vhost 有独立 Exchange/Queue/权限(类似 Namespace) |
| Connection | 客户端与 Broker 间的 TCP 长连接 |
| Channel(信道) | Connection 内的虚拟通道,实际执行 declare/send/consume,多路复用减少 TCP 开销 |
消息完整流转流程
- Producer 与 Broker 建立 TCP Connection → 开启 Channel
- 声明 Exchange(如不存在)、Queue、Binding
- Producer 发送消息到 Exchange,指定 Routing Key 和消息属性(持久化、优先级、TTL等)
- Exchange 根据类型 + Binding 规则匹配,将消息拷贝路由到符合条件的 Queue(s)
- 消息在 Queue 中等待,Consumer 订阅 Queue
- Broker 推(Push)消息给 Consumer(Basic.Consume),或 Consumer 主动拉(Basic.Get,不推荐)
- Consumer 处理完发送 ACK,Broker 标记消息可删除;若 NACK/无 ACK 可按配置重入队或进死信队列
⚠️ 注意 :Exchange 本身不存消息,若无匹配 Queue 且未设置备用交换器(Alternate Exchange),消息会被丢弃。
二、四种 Exchange 交换机详解
RabbitMQ 内置四种标准交换机类型,路由规则是核心区别。
1. Direct Exchange(直连交换机)------ 精确匹配
-
路由规则 :消息 Routing Key 必须与 Binding Key 完全相同(大小写敏感),才路由到对应 Queue
-
特点:简单高效,支持一个 Key 绑定多个 Queue(实现单播+伪多播)
-
典型场景 :
- 日志分级:
error→ 告警队列,info→ 归档队列 - 订单状态分发:
order.created→ 库存队列,order.paid→ 结算队列
- 日志分级:
-
默认交换机 :RabbitMQ 自带一个匿名
""Exchange(type=direct),自动用 Queue 名作 Binding Key,所以不显式声明交换机也能发消息Queue A ← bind "order.create"
Queue B ← bind "order.pay"msg(routingKey="order.create") → 只到 Queue A
msg(routingKey="order.pay") → 只到 Queue B
2. Fanout Exchange(扇形/广播交换机)------ 广播
- 路由规则 :忽略 Routing Key ,将消息复制并广播到所有绑定到此 Exchange 的 Queue
- 特点:性能最好(无匹配计算),彻底解耦发布者与订阅者拓扑
- 典型场景 :
-
系统公告 / 运维广播
-
订单创建后 → 同时通知库存、物流、营销、发邮件等多个系统
-
分布式缓存失效通知
Queue A、B、C 都 bind 到 fanout_exchange
发任意消息 → A、B、C 各收到一份拷贝
-
3. Topic Exchange(主题交换机)------ 通配符匹配 ⭐最灵活
- 路由规则 :Routing Key 用
.分隔单词(如order.created.vip),Binding Key 支持通配符:*------ 匹配恰好一个单词#------ 匹配零个或多个单词
- 特点:兼具精确与模糊匹配,适合多维度分类订阅
- 典型场景 :
-
日志系统:
log.error.#接收所有错误日志,*.usa.*接收美国区域消息 -
微服务事件总线:
user.*订阅用户相关所有事件,order.*.paid订阅各类订单支付Binding: Queue A ← "order.*.vip"
Binding: Queue B ← "order.#"routingKey="order.created.vip" → A✓ B✓
routingKey="order.paid.vip" → A✓ B✓
routingKey="order.created.normal" → A✗ B✓
routingKey="order.paid" → A✗ B✓(#匹配0词)
-
4. Headers Exchange(头交换机)------ 基于消息头属性匹配
- 路由规则 :忽略 Routing Key ,根据消息
headers(Map<String,Object>)匹配- 绑定时设
x-match参数:x-match = all→ 所有 header 键值对均匹配x-match = any→ 任意一个匹配即可
- 绑定时设
- 特点 :支持多条件复杂筛选,但性能低于其他三种,使用较少(Topic 常可替代)
- 典型场景 :需多属性组合路由,如
type=order AND priority=high
java
// 绑定时
Map<String,Object> headers = new HashMap<>();
headers.put("type", "order");
headers.put("priority", "high");
headers.put("x-match", "all");
channel.queueBind(queueName, headersExchange, "", headers);
// 发送时
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
.headers(new HashMap<String,Object>() {{
put("type", "order");
put("priority", "high");
}}).build();
channel.basicPublish("headers.ex", "", props, body);
四种交换机对比速查
| 类型 | 路由依据 | 匹配方式 | 性能 | 使用频率 | 典型场景 |
|---|---|---|---|---|---|
| Direct | Routing Key | 完全相等 | ★★★★ | ★★★★★ | 点对点、日志分级 |
| Fanout | 无(忽略Key) | 广播全部 | ★★★★ | ★★★★ | 广播通知、多系统联动 |
| Topic | Routing Key | */#通配符 |
★★★ | ★★★★★ | 分类订阅、事件总线 |
| Headers | Headers属性 | K-V全/任匹配 | ★★ | ★★ | 多条件复杂路由(少用) |
三、其他重要概念详解
Queue 属性
- Durable(持久化) :设为 true 时 Queue 元数据存磁盘,Broker 重启后保留(消息本身还需设
deliveryMode=2才持久化) - Exclusive(排他):仅允许当前 Connection 使用,连接关闭自动删除
- Auto-delete:最后一个 Consumer 取消订阅后自动删除
- 支持设置 x-message-ttl (消息过期时间)、x-max-length (队列最大长度)、x-dead-letter-exchange(死信交换机)
消息确认机制(ACK)
autoAck=true:Broker 发出即删,可能丢消息autoAck=false:Consumer 手动basic.ack,处理完才删;异常可basic.nack(requeue)重入队或丢弃 → 推荐生产环境使用
死信队列(DLQ --- Dead Letter Queue)
以下情况消息变"死信":
- 被 Consumer 拒绝/Nack 且不重入队
- 消息 TTL 过期
- 队列超出长度限制
死信交换机(DLX --- Dead Letter Exchange)
通过在 Queue 声明时设置 x-dead-letter-exchange 和 x-dead-letter-routing-key,死信会被转发到指定 DLX→DLQ,常用于延迟队列(结合 TTL( Time To Live)+DLX)和异常消息兜底处理。
Virtual Host(vhost)
- 同一 Broker 内逻辑隔离,不同 vhost Exchange/Queue 互不可见
- 常用于:多环境隔离(
/dev、/test、/prod)、多租户隔离
bash
rabbitmqctl add_vhost /prod
rabbitmqctl set_permissions -p /prod user ".*" ".*" ".*"
Connection & Channel
- Connection:TCP 连接,建立开销大
- Channel:轻量级虚拟通道,复用 Connection,每个线程建议用独立 Channel,避免并发问题
- 几乎所有 AMQP 操作(exchangeDeclare、queueDeclare、basicPublish、basicConsume)都在 Channel 上进行
Docker 部署 RabbitMQ 的「生产可用标准方案」
一、最快方式(测试 / 本地开发 ✅)
1️⃣ 一行命令启动(带 Web 管理界面)
bash
docker run -d \
--name rabbitmq \
-p 5672:5672 \
-p 15672:15672 \
rabbitmq:3.12-management
访问地址
| 类型 | 地址 |
|---|---|
| AMQP(程序用) | localhost:5672 |
| Web 管理台 | http://localhost:15672 |
默认账号
用户名:guest
密码:guest
⚠️ guest 用户只能 localhost 访问
二、推荐方式(生产环境 ✅✅)
1️⃣ 创建目录(数据持久化)
bash
mkdir -p /opt/rabbitmq/{data,logs}
2️⃣ docker-compose.yml(强烈推荐)
yaml
version: '3.8'
services:
rabbitmq:
image: rabbitmq:3.12-management
container_name: rabbitmq
restart: always
hostname: rabbitmq
environment:
RABBITMQ_DEFAULT_USER: admin
RABBITMQ_DEFAULT_PASS: Admin123!
RABBITMQ_DEFAULT_VHOST: /
ports:
- "5672:5672" # AMQP
- "15672:15672" # Web UI
volumes:
- /opt/rabbitmq/data:/var/lib/rabbitmq
- /opt/rabbitmq/logs:/var/log/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "ping"]
interval: 30s
timeout: 10s
retries: 5
启动:
bash
docker compose up -d
3️⃣ 登录 Web 控制台
http://服务器IP:15672
用户名:admin
密码:Admin123!
三、创建 vhost / 用户(生产必做 ✅)
进入容器:
bash
docker exec -it rabbitmq bash
创建 vhost
bash
rabbitmqctl add_vhost /prod
创建用户
bash
rabbitmqctl add_user app_user App@123
授权
bash
rabbitmqctl set_permissions -p /prod app_user ".*" ".*" ".*"
四、Spring Boot 对应配置 ✅
yaml
spring:
rabbitmq:
host: 服务器IP
port: 5672
username: app_user
password: App@123
virtual-host: /prod
五、确认 RabbitMQ 是否 OK ✅
bash
docker ps
docker logs rabbitmq
Web 页面能看到:
- Queues
- Exchanges
- Connections
✅ 说明部署成功
六、生产环境必须注意的 5 件事 ⚠️
| 项目 | 建议 |
|---|---|
| 数据目录 | 必须 volume 挂载 |
| 默认 guest | 禁用或限制 |
| 端口暴露 | 外网只开 5672 |
| Web 管理台 | 内网访问 / VPN |
| 内存 | 至少 2G |
七、你这套 Spring Cloud 延迟队列能用吗?
✅ 完全可以用
✅ TTL + DLX + 死信队列 不需要额外插件
✅ Docker 版本 ≥ 3.8 都没问题
八、一句话总结 ✅
Docker 部署 RabbitMQ 用
3.x-management镜像 + docker-compose + 数据卷 + 自定义用户,就是生产级方案。
rabbit 使用springcloud 创建队列 生成消息 交给交换机 进入不同得队列 之后消费普通队列消息 和消费死信队列消息代码
下面覆盖你关心的 全部点:
✅ Spring Cloud / Spring Boot
✅ 创建 延迟队列(TTL)
✅ 创建 死信队列(DLQ)
✅ 创建 普通业务队列
✅ 交换机 → 不同队列
✅ 生产消息
✅ 消费 普通队列
✅ 消费 死信队列(关单)
一、依赖(pom.xml)
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
二、application.yml
yaml
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
三、RabbitMQ 配置类(核心 ✅)
只在这一处声明所有 Queue / Exchange / Binding
java
@Configuration
public class RabbitConfig {
// ================= 交换机 =================
public static final String ORDER_EXCHANGE = "order.exchange";
// ================= 普通队列(支付成功) =================
public static final String ORDER_PAY_QUEUE = "order.pay.queue";
public static final String ORDER_PAY_KEY = "order.pay";
// ================= 延迟队列(30分钟) =================
public static final String ORDER_DELAY_QUEUE = "order.delay.queue";
public static final String ORDER_DELAY_KEY = "order.delay";
// ================= 死信队列(关单) =================
public static final String ORDER_CLOSE_QUEUE = "order.close.queue";
public static final String ORDER_CLOSE_KEY = "order.close";
// ================= 死信交换机 =================
public static final String ORDER_DLX = "order.dlx";
/* ========== 交换机 ========== */
@Bean
public DirectExchange orderExchange() {
return new DirectExchange(ORDER_EXCHANGE, true, false);
}
@Bean
public DirectExchange orderDlx() {
return new DirectExchange(ORDER_DLX, true, false);
}
/* ========== 普通队列(支付成功) ========== */
@Bean
public Queue orderPayQueue() {
return new Queue(ORDER_PAY_QUEUE, true);
}
@Bean
public Binding orderPayBinding() {
return BindingBuilder.bind(orderPayQueue())
.to(orderExchange())
.with(ORDER_PAY_KEY);
}
/* ========== 死信队列(关单) ========== */
@Bean
public Queue orderCloseQueue() {
return new Queue(ORDER_CLOSE_QUEUE, true);
}
@Bean
public Binding orderCloseBinding() {
return BindingBuilder.bind(orderCloseQueue())
.to(orderDlx())
.with(ORDER_CLOSE_KEY);
}
/* ========== 延迟队列(重点⭐) ========== */
@Bean
public Queue orderDelayQueue() {
Map<String, Object> args = new HashMap<>();
args.put("x-message-ttl", 30 * 60 * 1000); // 30分钟
args.put("x-dead-letter-exchange", ORDER_DLX);
args.put("x-dead-letter-routing-key", ORDER_CLOSE_KEY);
return new Queue(ORDER_DELAY_QUEUE, true, false, false, args);
}
@Bean
public Binding orderDelayBinding() {
return BindingBuilder.bind(orderDelayQueue())
.to(orderExchange())
.with(ORDER_DELAY_KEY);
}
}
四、发送消息(生产者)
1️⃣ 下单 → 进延迟队列
java
@Component
@RequiredArgsConstructor
public class OrderProducer {
private final RabbitTemplate rabbitTemplate;
public void createOrder(Long orderId) {
String msg = "orderId=" + orderId;
rabbitTemplate.convertAndSend(
RabbitConfig.ORDER_EXCHANGE,
RabbitConfig.ORDER_DELAY_KEY,
msg
);
}
}
2️⃣ 支付成功 → 进普通队列
java
public void paySuccess(Long orderId) {
String msg = "orderId=" + orderId;
rabbitTemplate.convertAndSend(
RabbitConfig.ORDER_EXCHANGE,
RabbitConfig.ORDER_PAY_KEY,
msg
);
}
✅ 支付成功只改数据库,不删 MQ 消息
五、消费普通队列(支付成功)
java
@Component
@Slf4j
@RabbitListener(queues = RabbitConfig.ORDER_CLOSE_QUEUE)
public void closeOrder(String msg, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag) {
try {
// 1. 业务处理
handleOrder(msg);
// 2. 成功 → ACK
channel.basicAck(tag, false);
} catch (Exception e) {
log.error("关单失败", e);
// 3. 失败 → NACK(不重入队,进 DLQ)
try {
channel.basicNack(tag, false, false);
} catch (IOException ex) {
log.error("NACK 失败", ex);
}
}
}
六、消费死信队列(30分钟未支付 → 关单 ✅)
java
@Component
@Slf4j
public class OrderCloseConsumer {
@RabbitListener(queues = RabbitConfig.ORDER_CLOSE_QUEUE)
public void closeOrder(String msg, Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
Long orderId = extractOrderId(msg);
// ✅ 查数据库
Order order = orderMapper.selectById(orderId);
if (order != null && order.getStatus() == UNPAID) {
orderMapper.updateStatus(orderId, CLOSED);
log.info("订单超时关闭:{}", orderId);
}
channel.basicAck(tag, false);
}
}
✅ 这是标准答案
✅ 不删 MQ
✅ 用 DB 状态兜底
七、完整消息流向(你这套代码的效果)
下单
↓
order.delay.queue(TTL=30min,❌无消费者)
↓ 30分钟
order.dlx
↓
order.close.queue(✅消费)
↓
DB 未支付 → 关闭订单
支付成功
↓
order.pay.queue(✅消费)
↓
支付业务处理
八、一句话总结(你可以放心用)
✅ 延迟队列不消费
✅ 死信队列才消费
✅ 支付成功只改 DB
✅ 30 分钟到 DLQ 再关单
MQ消息堆积处理方案
一、什么叫 RabbitMQ 消息堆积?
生产者发消息速度 > 消费者处理速度 → Queue 中 Ready 消息持续增长
Web 管理台看到:
Ready很大Unacked不大- Consumers 在线但处理不过来
二、先确认是哪种原因(很重要)
✅ 常见原因
| 原因 | 表现 |
|---|---|
| 消费者太慢(IO / DB / 外部接口) | Ready↑,CPU 不高 |
| 消费者数量太少 | Ready↑ |
| 消费者挂了 / ACK 没回 | Ready 不变 / Unacked↑ |
| 突发流量(秒杀 / 批量导入) | 短时间堆积 |
| 消息体太大 | 内存 / 磁盘压力大 |
| 消费者异常一直重试 | Unacked↑ / 阻塞 |
👉 先查 RabbitMQ Management → Queues → Graph
三、消息堆积的处理方案(按优先级)
✅ 方案 1:增加消费者(最常用 ✅)
① 多启几个消费者实例(横向扩容)
yaml
spring:
rabbitmq:
listener:
simple:
concurrency: 2
max-concurrency: 8
或干脆:
- 起 2~4 个 Pod / 进程
- 同 Queue 多 Consumer 竞争消费
✅ RabbitMQ 自动 Round-Robin
✅ 方案 2:提高 prefetch(批量拉取)
默认 prefetch=1(太保守)
yaml
spring:
rabbitmq:
listener:
simple:
prefetch: 50 # 或 100
⚠️ 注意:
- 不要太大(内存 / Unacked)
- 配合 ACK 使用
"我(消费者)一次向 MQ 申请拿 50 条消息(Prefetch=50),我拿着这 50 条去慢慢处理,处理完一条我就手动喊一声 ACK 告诉 MQ 可以删了。"
✅ 方案 3:优化消费者处理逻辑(治本)
- 减少 DB 操作(批量写)
- 异步 / 并行
- 去掉同步 HTTP 调用
- 不必要逻辑移出 MQ 消费线程
❌ 典型反例:
java
for (Order o : list) {
restTemplate.postForObject(...); // ❌ 慢
}
✅ 方案 4:队列拆分(业务隔离)
原来:
order.queue ← 创建 + 支付 + 取消 + 关单
拆成:
order.create.queue
order.pay.queue
order.close.queue
✅ 互不影响
✅ 可单独扩容
✅ 方案 5:限流 / 削峰(生产者侧)
- 前端限流
- 网关限流
- 批量任务错峰(夜间跑)
- 使用 延迟队列分散峰值
✅ 方案 6:已有大量堆积时"追上来"
临时措施 ✅
- 临时扩容消费者(2~5倍)
- 提高 prefetch
- 暂时简化消费逻辑(只落库 / 只标记)
- 追平后再恢复正常
⚠️ 不要:
- 删队列
- 清消息(除非可丢失)
✅ 方案 7:设置队列上限 / TTL(防雪崩)
java
x-max-length = 100000
x-overflow = drop-head / reject-publish
✅ 防止 MQ 把磁盘 / 内存拖垮
四、如果消费者挂了导致堆积
| 现象 | 处理 |
|---|---|
| Ready↑,Unacked=0 | 重启消费者 |
| Unacked↑ | 检查 ACK / NACK 逻辑 |
| 一直 NACK(requeue=true) | 改为有限重试 + DLQ |
五、延迟队列场景(你之前那个)要特别注意 ⚠️
❌ 延迟队列(TTL 队列)堆积是正常的
- 消息在等 TTL 到期
- 不算异常
✅ 只有 关单队列(DLQ)堆积 需要处理
六、防堆积的最佳实践(生产总结)
✅ 多 Consumer + prefetch
✅ 消费逻辑轻
✅ 业务拆分队列
✅ 关单靠 DB 状态,不重消费
✅ 监控:Ready > 阈值 → 告警
✅ 限流 + 错峰
七、一句话总结 ✅
RabbitMQ 消息堆积先查原因 → 优先加消费者 / 提高 prefetch / 优化消费逻辑 → 必要时队列拆分 / 限流 → 已有堆积临时扩容追平,不删消息
① RabbitMQ 整体流程
Producer → Exchange → RoutingKey/Binding → Queue → Consumer → ACK
② 四种交换机区别 + 使用场景
Direct / Fanout / Topic / Headers(尤其 Topic 通配符)
③ 延迟队列怎么做 & 为什么延迟队列不消费
TTL + DLX,支付成功只改 DB,关单时查状态
④ 消息不丢失怎么保证
Exchange durable + Queue durable + Message PERSISTENT + manual ACK + DLX
⑤ 消息重复 / 幂等怎么处理
订单号唯一约束 / 状态判断 / 乐观锁
⑥ 消息堆积怎么处理
加消费者 / prefetch / 队列拆分 / 限流