--- tags: [test/review, mq, rabbitmq, pull-model, qos, prefetch, backpressure, consumer-balance] create time: 2026-08-09 12:00 --- # 推拉结合消费模式_测试题 ## 概述 本测试覆盖 RabbitMQ 消费模型的本质(Push vs Pull 混合理解)、QoS 预取策略、背压处理和消费者负载均衡。共 10 道题:6 道选择题、3 道填空题、1 道简答题。 --- ## 一、选择题(6道,由浅入深) > **难度阶梯**: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景 ### Q1(基础)— 考察定义层面 RabbitMQ Consumer API 名为 `basic.consume`(拉取)但实际运行模型是 Server Push(服务端推送)。以下说法正确的是: A. `basic.consume` 和 `basic.get` 的行为完全相同 B. `basic.consume` 建立订阅后 Broker 持续主动投递,`basic.get` 每次调用阻塞获取单条消息 C. `basic.consume` 只能获取一次就断开连接 D. `basic.get` 是默认的生产者发送方法 ### Q2(基础)— 考察行为判断 设置 `prefetch_count = 1` 可以实现公平分发(Fair Dispatch),其核心原因是: A. Broker 会随机选择消费者分配消息 B. A 每处理完一条并发 ack 后才收到下一条,自然形成速度匹配 C. prefetch=1 时所有消息排队等候直到第一个消费者空闲 D. prefetch=1 强制只有一个消费者活跃 ### Q3(进阶)— 考察核心原理 `global=true` 是 Prefetch 设置中的一个遗留参数,以下哪一项描述了在多 Channel 场景下使用 global=true 可能导致的意外行为? A. prefetch 只对单个 Channel 生效,不会跨 Channel 共享配额 B. prefetch 对整个连接(而非单个 Channel)生效,导致一个 Channel 消耗了所有配额时其他 Channel 无法获得新消息 C. global=true 会使 prefetch_count 失效 D. global=true 只在 Fanout Exchange 中有效 ### Q4(进阶)— 考察对比辨析 以下哪种预取值范围最适合通用生产环境? A. prefetch=1 B. prefetch=0 C. prefetch=10~50 D. prefetch=10000+ ### Q5(深入)— 考察场景推理 一个日终跑批系统需要从数据库全量读取商品信息并通过 MQ 推送到缓存集群预热。数据量大但每条消息处理简单。同时另一个即时订单状态推送系统要求低延迟。这两个场景分别适合的 prefetch 值是: A. 两者都用 prefetch=1 B. 跑批用 prefetch=200,订单推送用 prefetch=3 C. 跑批用 prefetch=3,订单推送用 prefetch=200 D. 两者都用 prefetch=0(无限) ### Q6(深入)— 考察源码级别细节 在 `basic.consume` 建立的流控窗口机制中,Window 耗尽时 Broker 会发生什么? A. Broker 立即关闭 TCP 连接 B. Broker 暂停向该 Channel 投递直到窗口回收(ack 释放槽位) C. Broker 将多余消息转移到其他 Channel D. Broker 丢弃超出的消息 --- ## 二、填空题(3道) ### F1 — 填空 设 prefetch = N 时,Broker 可以在没有收到 ack 的情况下最多向该 Channel 发送 ______ 条消息累积在未确认状态。当 ack 一条消息后 unacked 数减一,Broker 再补发一条。 > **提示**: 这就是 prefetch 值本身的含义。 ### F2 — 填空 同一个 Queue 可以有多个消费者构成 Consumer Group,RabbitMQ 以 ______ 方式将消息均匀分配给各消费者。但在 prefetch=1 时可能出现只有一个消费者活跃而另一个空等的情况。 > **提示**: 这种分发方式的英文术语是什么? ### F3 — 填空 根据调优黄金法则:先设 prefetch=1 观察各消费者的处理耗时分布,再根据 p99 耗时最高的那个消费者来估算合适的 batch size,初始设为预估值的 ______ 倍即可。 > **提示**: 回顾文档中的调优经验。 --- ## 三、简答题(1道) ### S1 你正在为一家在线教育公司设计课程点播系统的消息处理 pipeline。系统有以下特征: - 用户观看视频后会触发埋点事件(播放进度、点赞、评论),每秒约 5000 条 - 埋点数据处理流程:去重 → 聚合 → 写入时序数据库 - 去重操作涉及 Redis 分布式锁,耗时约 50ms - 聚合操作相对较快(约 5ms) - 写入时序数据库是 IO 密集型操作(约 20ms) - 高峰期总处理耗时约 75ms/条消息 - 当前部署了 5 个消费者实例 请设计 QoS 配置方案并回答: 1. 整体 prefetch 值应该设置多少?为什么? 2. 是否需要对不同阶段的处理进行拆分(多队列串联)? 3. prefetch 过大或过小各自会带来什么问题? > **答题框架提示**: 1. 基于单条消息处理耗时计算合适的 prefetch 2. 考虑是否需要将耗时长的阶段拆出独立队列 3. 大 prefetch 和小 prefetch 的权衡分析 --- ## 参考答案与解析 ### 选择题答案 | 题号 | 正确答案 | 解析 | |------|---------|------| | Q1 | B | `basic.consume` 建立订阅后 Broker 持续主动投递(Push),适用于大多数场景。`basic.get` 每次调用阻塞获取单条消息(Pull),适用于管理界面和健康检查等非实时场景。API 名为 consume 但实质是 Push,源于 AMQP 协议早期约定。 | | Q2 | B | prefetch=1 实现 Fair Dispatch 的核心机制:A 每处理完一条、发一个 ack,才会收到下一条,自然形成速度匹配。如果 prefetch=N(大数值),Broker 可能在短时间内把 N 条消息全发给 A 而 B 空闲等待。 | | Q3 | B | global=true 是对整个连接(而非单个 Channel)生效,在多 Channel 场景下会导致意外行为。现代客户端中一律设为 false,作用于单个 Channel。这是遗留参数,不建议使用。 | | Q4 | C | prefetch=10~50 是通用生产环境默认值。prefetch=1 吞吐量较低适合处理耗时差异大的场景;prefetch=100~500 吞吐最高但内存压力大;prefetch=0(不设置)为无限值严禁在生产中使用。 | | Q5 | B | 跑批场景:数据量大但处理简单,适合高吞吐配置 prefetch=200 配合批量更新 Redis pipeline。订单推送:latency 优先级高于 throughput,设置 prefetch=3 让消费者尽快处理完再拿下一条。 | | Q6 | B | 流控窗口耗尽时,Broker 暂停向该 Channel 投递直到窗口回收。这是内建的背压机制——消费者发送 basic.ack 后窗口恢复,或者 window refill 后继续投递。不会丢消息也不会断连。 | ### 填空题答案 | 题号 | 答案 | 解析 | |------|------|------| | F1 | N | prefetch_count 定义了单个 Channel 上允许的最大未确认消息数。这 N 条消息累积在 unacked 状态,ack 一条后 Broker 再补发一条。prefetch 越大意味着降低网络 RTT 开销但也增加了内存压力和崩溃损失量。 | | F2 | Round-Robin(轮询) | RabbitMQ 以轮询方式将消息平均分配给同一 Queue 的各消费者。但 Round-Robin 不一定是公平的——处理快的消费者实际上承担更多工作量,这正是 prefetch=1 要解决的问题。 | | F3 | 2~3 | 调优黄金法则:先设 prefetch=1 观察各消费者的处理耗时分布,再根据 p99 耗时最高的消费者估算合适的 batch size,初始设为预估值的 2~3 倍。之后通过监控 unacked 数量和 queue depth 微调。 | ### 简答题参考答案 S1:**参考答案要点**: 1. 单条消息总处理耗时约 75ms,5 个消费者实例理论上可支撑 5 / 75ms ≈ 66 QPS。但实际需求为 5000 QPS,远超出单节点处理能力。prefetch 建议设置为 10~20:太小无法满足吞吐需求,太大会导致消息积压在消费者内存中。初始可按 prefetched messages ≤ 处理耗时 × prefetch_count 来估算。 2. 需要拆分!去重步骤涉及 Redis 分布式锁是串行瓶颈(50ms),应将去重作为独立的第一层消费者队列(快速筛选有效请求),聚合和写库放到第二层队列做批处理。这样可以大幅缓解单机瓶颈。 3. prefetch 过大的问题:Broker 可以积压更多消息到消费者内存,降低每次投递的往返开销但也增加了内存压力、崩溃恢复时的损失量以及处理时间过长导致 unacked 消息占满 prefetch 配额的风险。prefetch 过小的问题:串行节奏限制吞吐量,网络 RTT 开销占比增大。 **评分标准**:答出任意 2 个要点即可得满分;完全正确需覆盖 prefetch 配置、队列拆分策略和大/小 prefetch 权衡三个维度。 ## 关联笔记 - [[04.MQ/rabbitmq/消息持久化与可靠性投递]] - [[04.MQ/rabbitmq/ACK 确认与死信队列]] - [[04.MQ/rabbitmq/Exchange 路由机制]]