164 lines
8.6 KiB
Markdown
164 lines
8.6 KiB
Markdown
|
|
---
|
|||
|
|
tags: [test/review, mq, rabbitmq, publisher-confirm, message-persistence, rabbitmq-transaction, return-callback]
|
|||
|
|
create time: 2026-08-09 12:00
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 消息持久化与可靠性投递_测试题
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
本测试覆盖 RabbitMQ 消息从生产者到消费者的完整链路中保证可靠性的三大支柱:Exchange/Queue 持久化、消息 persistent 标记和 Publisher Confirm 机制。共 10 道题:6 道选择题、3 道填空题、1 道简答题。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 一、选择题(6道,由浅入深)
|
|||
|
|
|
|||
|
|
> **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
|
|||
|
|
|
|||
|
|
### Q1(基础)— 考察定义层面
|
|||
|
|
|
|||
|
|
RabbitMQ 消息持久化的三个环节依次是:
|
|||
|
|
|
|||
|
|
A. 发送端加密 → 网络传输加密 → 存储端加密
|
|||
|
|
B. Exchange durable 声明 → Queue durable 声明 → 消息 DeliveryMode=2
|
|||
|
|
C. 消息签名 → Exchange 验证 → Queue 存储
|
|||
|
|
D. 生产者确认 → Broker fsync → 消费者 ACK
|
|||
|
|
|
|||
|
|
### Q2(基础)— 考察行为判断
|
|||
|
|
|
|||
|
|
仅设置 Queue durable=true 但消息的 DeliveryMode=1(transient),服务器重启后这些消息会怎样?
|
|||
|
|
|
|||
|
|
A. 消息会保留在磁盘中因为队列本身是持久的
|
|||
|
|
B. 消息会被丢弃因为瞬态消息不会写入磁盘
|
|||
|
|
C. 消息会被转移到另一个临时队列
|
|||
|
|
D. 消息会以压缩格式保存在内存中
|
|||
|
|
|
|||
|
|
### Q3(进阶)— 考察核心原理
|
|||
|
|
|
|||
|
|
Publisher Confirm 批量确认模式相比单条确认模式的主要优势是什么?
|
|||
|
|
|
|||
|
|
A. 能保证"恰好一次"语义而单条不能
|
|||
|
|
B. 吞吐量接近未开启 Confirm 的水平,性能差距数倍甚至十倍以上
|
|||
|
|
C. 不需要建立 Channel 连接即可工作
|
|||
|
|
D. 支持事务回滚语义
|
|||
|
|
|
|||
|
|
### Q4(进阶)— 考察对比辨析
|
|||
|
|
|
|||
|
|
关于 RabbitMQ 的 Confirm vs Transaction 两种可靠投递方式,以下哪项对比是错误的?
|
|||
|
|
|
|||
|
|
A. Confirm 采用异步批量确认,Transaction 采用同步提交
|
|||
|
|
B. Transaction 的资源开销更高,需要维护完整的事务日志和回滚状态
|
|||
|
|
C. Confirm 能保证恰好一次语义,Transaction 只能做到最多一次
|
|||
|
|
D. 生产环境中几乎不推荐使用 Transaction 模式
|
|||
|
|
|
|||
|
|
### Q5(深入)— 考察场景推理
|
|||
|
|
|
|||
|
|
一个订单支付推送系统使用 RabbitMQ 将支付结果通知给物流、库存等多个下游系统。在生产者配置中,如果 exchange 存在但没有绑定的队列能匹配该 routing key,且消息设置了 mandatory=false,会发生什么?
|
|||
|
|
|
|||
|
|
A. ReturnCallback 被触发,消息退回给生产者
|
|||
|
|
B. 消息被 Broker 静默丢弃,没有任何通知
|
|||
|
|
C. ConfirmCallback 收到 nack 通知
|
|||
|
|
D. 消息自动路由到死信队列
|
|||
|
|
|
|||
|
|
### Q6(深入)— 考察源码级别细节
|
|||
|
|
|
|||
|
|
在 Go 中使用 amqp.go 库实现 Confirm + Return 回调时,以下代码片段的作用是什么?
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
confirms := ch.NotifyPublish(nil)
|
|||
|
|
for conf := range confirms {
|
|||
|
|
if conf.Ack {
|
|||
|
|
log.Printf("消息 delivery-tag=%d 已确认", conf.DeliveryTag)
|
|||
|
|
} else {
|
|||
|
|
log.Printf("消息 delivery-tag=%d 未被确认", conf.DeliveryTag)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
A. 注册 ReturnCallback 处理路由失败的消息
|
|||
|
|
B. 注册 ConfirmCallback 通道,逐条接收 Broker 对每条消息的处理结果
|
|||
|
|
C. 向所有生产者广播消息
|
|||
|
|
D. 监控 Broker 的健康状态
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 二、填空题(3道)
|
|||
|
|
|
|||
|
|
### F1 — 填空
|
|||
|
|
|
|||
|
|
RabbitMQ 消息的 DeliveryMode 为 ______ 时表示持久化消息,只有设置为这个值的消息在抵达 Queue 后才会刷盘到磁盘。
|
|||
|
|
|
|||
|
|
> **提示**: 取值为 1 或 2。
|
|||
|
|
|
|||
|
|
### F2 — 填空
|
|||
|
|
|
|||
|
|
只有同时开启 mandatory=true,ReturnCallback 才会在消息因无法路由而被退回时被触发。ConfirmCallback 告诉生产者消息是否被 Broker 安全接收(路由完成),而 ReturnCallback 处理强制性消息无法路由的情况——它区分了"Exchange 不存在"和"Exchange 存在但无绑定队列"这两种情况。
|
|||
|
|
|
|||
|
|
> **提示**: 思考 mandatory 参数在这个回调中的作用。
|
|||
|
|
|
|||
|
|
### F3 — 填空
|
|||
|
|
|
|||
|
|
如果需要"恰好一次"语义,正确做法是:______ 作为投递保障加上业务层幂等键(如 orderId 唯一索引)兜底。
|
|||
|
|
|
|||
|
|
> **提示**: 不是 Transaction,而是另一种更轻量的机制。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 三、简答题(1道)
|
|||
|
|
|
|||
|
|
### S1
|
|||
|
|
|
|||
|
|
你正在为一个金融转账系统设计基于 RabbitMQ 的消息通知服务。转账成功后需要将交易记录通过 MQ 通知风控系统和审计系统。该系统有以下要求:
|
|||
|
|
- 绝对不能丢失任何一条交易通知
|
|||
|
|
- 下游系统具备幂等处理能力(可以安全重复消费)
|
|||
|
|
- 高吞吐需求(峰值 QPS 5000+)
|
|||
|
|
|
|||
|
|
请设计一个完整的可靠性投递方案,回答以下问题:
|
|||
|
|
1. Exchange、Queue 和消息的持久化如何配置?
|
|||
|
|
2. 选择 Confirm 还是 Transaction?为什么?
|
|||
|
|
3. Nack 的消息如何处理?
|
|||
|
|
4. 如何配合业务幂等性设计确保"恰好一次"的效果?
|
|||
|
|
|
|||
|
|
> **答题框架提示**:
|
|||
|
|
1. 三阶段持久化的具体配置
|
|||
|
|
2. Confirm 模式的选择理由及批量策略
|
|||
|
|
3. nack 的重试和补偿机制
|
|||
|
|
4. 业务层幂等键的设计思路
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 参考答案与解析
|
|||
|
|
|
|||
|
|
### 选择题答案
|
|||
|
|
|
|||
|
|
| 题号 | 正确答案 | 解析 |
|
|||
|
|
|------|---------|------|
|
|||
|
|
| Q1 | B | 三个环节:Exchange 声明 durable=true、Queue 声明 durable=true、消息 DeliveryMode=2。三者缺一不可,任何一个环节未持久化都导致丢消息风险。A 讲的是加密而非持久化;C/D 涉及其他机制。 |
|
|||
|
|
| Q2 | B | 常见误解:仅设置 Queue durable 并不能保证消息不丢。如果消息 DeliveryMode=1(transient),即使队列本身是持久的,这些瞬态消息在服务器重启时也会被丢弃。持久化是队列元数据和消息内容两回事。 |
|
|||
|
|
| Q3 | B | 批量 Confirm 一次发送多条消息一次性收到确认回调,吞吐量接近未开启 Confirm 的水平。单条确认串行等待 ack/nack 吞吐量极低。实际性能差距可达数倍甚至十倍以上。 |
|
|||
|
|
| Q4 | C | 反了!无论是 Confirm 还是 Transaction 都不够保证恰好一次。Confirm 最多一次(需重试才能至少一次),Transaction 配合回滚可做到更接近恰好一次但仍需业务幂等兜底。这是面试高频考点。 |
|
|||
|
|
| Q5 | B | mandatory=false 时,如果 Exchange 存在但没有匹配的 Queue,消息被 Broker 静默丢弃,不会触发任何回调。只有 mandatory=true 时才会触发 ReturnCallback 退回消息。A 错误——mandatory=false 不会触发 Return。 |
|
|||
|
|
| Q6 | B | NotifyPublish 注册一个 Confirmation 通道,每个发出的消息对应一个 Confirmation 对象,其 Ack 字段为 true 表示 Broker 已成功处理(路由完成),false 则说明未被确认(如 Exchange 不存在)。这是 Confirm 的核心结构。 |
|
|||
|
|
|
|||
|
|
### 填空题答案
|
|||
|
|
|
|||
|
|
| 题号 | 答案 | 解析 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| F1 | 2 | DeliveryMode=2 表示 persistent(持久化),DeliveryMode=1 表示 transient(瞬态)。持久化消息在抵达 Queue 后会刷盘而非仅仅留在内存 buffer 中。但这会带来明显的性能代价(大约 10 倍吞吐下降)。 |
|
|||
|
|
| F2 | mandatory | 只有同时开启 mandatory=true,ReturnCallback 才会在路由失败时被触发。mandatory 控制的是"消息是否允许被丢弃"——true 表示不允许丢弃,必须退回或报错;false 表示允许 Broker 静默丢弃无法路由的消息。 |
|
|||
|
|
| F3 | Confirm | 面试回答要点:如果需要"恰好一次"语义不要指望 RabbitMQ 本身保证——无论 Confirm 还是 Transaction 都不够。正确做法是 Confirm 作为投递保障 + 业务层幂等键(如 orderId 唯一索引)兜底。这才是工业级方案的思路。 |
|
|||
|
|
|
|||
|
|
### 简答题参考答案
|
|||
|
|
|
|||
|
|
S1:**参考答案要点**:
|
|||
|
|
1. Exchange 和 Queue 均声明 durable=true 防止服务重启丢数据;消息设置 DeliveryMode=2(persistent)确保磁盘持久化。
|
|||
|
|
2. 选择 Publisher Confirm 而非 Transaction。原因:Confirm 异步批量确认吞吐量大(峰值 QPS 5000+ 完全够用),资源占用低,主流客户端支持成熟。Transaction 同步阻塞吞吐不够且资源开销大。
|
|||
|
|
3. Nack 的消息放入本地重试表(数据库),定时任务扫描并重试。超过最大重试次数后进入死信队列人工介入。
|
|||
|
|
4. 业务幂等设计:每条交易通知携带唯一的 orderId + 目标系统标识作为幂等键。下游系统在数据库中建立联合唯一索引(order_id, target_system)。重复收到的消息因违反唯一约束而被拒绝,不会产生副作用。
|
|||
|
|
|
|||
|
|
**评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖三阶段持久化、Confirm 选择理由、nack 处理策略和业务幂等设计四个维度。
|
|||
|
|
|
|||
|
|
## 关联笔记
|
|||
|
|
- [[04.MQ/rabbitmq/ACK 确认与死信队列]]
|
|||
|
|
- [[04.MQ/rabbitmq/Exchange 路由机制]]
|
|||
|
|
- [[04.MQ/rabbitmq/推拉结合消费模式]]
|