Files
autumn-recruitment/04.MQ/rabbitmq/消息持久化与可靠性投递_test.md

164 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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/推拉结合消费模式]]