消息可靠性
消息可靠性涵盖发布、保存、消费和进度确认。本文以 Kafka 4.1 与 RabbitMQ 4.1 为例,负责各阶段确认和失败恢复。
1. 面试核心
先记住这几条,再读正文- 发布与消费确认。 RabbitMQ publisher confirm 确认发布阶段,consumer ack 确认消费阶段。卡 · 综合题
- 不可路由消息。 mandatory 发布的不可路由消息,会先 basic.return 再 publisher confirm。卡 · 生产者确认
- 副本确认。 Kafka 的 acks=all 等待 ISR 确认,min.insync.replicas 限定最低副本数。卡 · 生产者确认
- 消费进度。 消费完成后再确认,Kafka 只推进连续完成范围的 offset。卡 · 消费者确认时机
- 重试与死信。 延迟重试保留原消息 ID,死信存放终止重试的失败消息。
2. 生产者确认
RabbitMQ publisher confirm 与 consumer ack 相互独立。可路由消息被所有目标队列接收后,broker 才确认发布。持久消息进入持久队列时,还涉及持久化确认。quorum queue 的确认要求副本多数接受。
不可路由消息也会得到 publisher confirm。发布时设置 mandatory,可接收 basic.return。客户端应同时处理返回消息和确认结果。
Kafka 的 acks=all 等待当前 ISR 满足确认条件。配合 min.insync.replicas=2,可要求至少两个同步副本。ISR 数量不足时,写入返回副本不足错误。
副本数为 3、ISR 为 3 时,acks=all 等待 ISR 中全部副本。min.insync.replicas=2 并非只等待任意两个。ISR 收缩为 1 时,写入失败而非降为单副本成功。
enable.idempotence=true 去重生产者协议重试。Kafka 4.1 要求 acks=all、retries 大于 0。还要求 max.in.flight.requests.per.connection<=5。应用再次主动发送同一业务消息,仍需业务 ID 去重。
业务提交与消息发布的双写窗口可用 Outbox 处理。数据库事务同时保存业务变化和待发布事件。后台发布失败后,根据事件记录继续尝试。
3. 消费者确认时机
先提交业务,再确认消费进度,可避免提前跳过处理。业务完成后、确认前崩溃会重复,处理方式见消息幂等性。
Kafka committed offset 表示恢复后要读取的下一位置。假设 10、11、12 三条记录并行处理。10 和 12 已完成,11 尚未完成,此时最多提交 11。提交 13 会让重启后跳过 11。
采用手动完成追踪时,设置 enable.auto.commit=false。应用逐分区维护连续完成位置,再提交 offset。
RabbitMQ delivery tag 只在当前 Channel 内有效。消费者应在接收消息的 Channel 上确认。multiple=true 会确认该 tag 及之前的未确认投递。因此并发任务也需防止确认越过未完成项。
prefetch 限制未确认投递数量。增大 prefetch 可提高在途并发,也增加内存与故障重投量。
4. 即时重试
短暂连接故障可进行有限重试,并使用退避和抖动。重试必须服从总处理时限。参数或 schema 错误应进入可观察的失败路径。
立即 requeue 会让失败消息快速重投。持续循环会占满消费者,并反复冲击下游。
5. 延迟重试
长等待可进入 retry topic 或 retry queue。消息保留原 ID,并记录次数和下次执行时间。例如按 10 秒、1 分钟、10 分钟分层重试。
Kafka retry topic 本身不会按时间自动延迟交付。消费端或调度组件需要检查到期时间。RabbitMQ 可用 TTL 配合 DLX 实现等待队列。单条消息 TTL 混用长短延迟时,会出现队头等待。
将失败消息移入重试通道,会改变原处理顺序。顺序敏感业务需决定是否暂停同键后续消息。
6. 死信队列
RabbitMQ 配置 DLX 后,可转发被拒绝且不 requeue 的消息。消息过期、队列长度限制也可触发死信。quorum queue 超过 delivery-limit 时同样可进入死信。
应用重试次数超限,需要显式转入对应失败路径。Kafka 的死信 topic 由应用或框架实现。
死信应保留原消息 ID、业务键、来源和错误类别。另记录尝试次数、首次与最后失败时间。修复后需要限速重放,并保留审计结果。
7. 死信转发失败
默认 dead-lettering 以 at-most-once 转发。转发到目标失败时,消息存在丢失窗口。只配置 DLX 尚缺少转发确认保障。
RabbitMQ 4.1 的源 quorum queue 可启用以下策略:
dead-letter-strategy=at-least-once。overflow=reject-publish。- 配置
dead-letter-exchange和有效路由。 - 确认 stream_queue feature flag 已启用。
源队列保留消息,直到内部转发获得确认。目标故障时消息继续占用源队列容量。因此还需限制容量并监控积压。目标收到重复消息时,仍需幂等处理。
转发会保留原消息的 delivery mode。目标重启后仍需保存消息时,应使用持久目标队列。源发布消息也应设置持久化。
8. 重放
重放保留原始消息 ID,以便消费端去重。另增加执行批次标识,用于跟踪本次恢复。
开始前核对旧消息的版本和消费逻辑。重放速率受下游剩余容量约束。顺序敏感数据按键处理,并支持暂停和断点续跑。
9. 端到端指标
分别记录发布失败、路由失败和副本状态。消费侧观察 lag、未确认量、失败率和最老消息年龄。重试与死信通道也要监控转发和目标增量。
关键链路通过事件 ID 对照最终业务结果。broker 接收成功只完成中间一段交付。
10. 常见问题
10.1 发布确认与路由结果
publisher confirm 可确认不可路由消息。mandatory 与 basic.return 用于暴露这类失败。之后的消费完成由 consumer ack 单独表达。
10.2 立即重新入队
瞬时重投适合很短的故障恢复窗口。持续失败应延迟并限制次数。永久错误进入死信或人工修复状态。
11 · 面试题卡片
11.1 如何设计消息确认、重试和死信流程
出现公司:Shopee、京东
题型:综合题
考察重点
- 生产确认与消费确认的独立边界。
- 副作用提交和 ack、offset 提交的顺序。
- 延迟重试、死信、重放和端到端核对。
参考回答
发布确认、消费确认和业务提交是独立阶段。
RabbitMQ 同时检查 publisher confirm 与路由返回。Kafka 使用 acks=all 并配置足够的同步副本。
业务提交后再确认,重复由业务幂等处理。重试分为有限即时重试和延迟重试。永久失败进入死信,转发、告警和限速重放也要覆盖。最终用消息 ID 核对业务结果。
11.2 RabbitMQ 发布确认成功,为什么目标队列仍没有消息?
出现公司:暂无已核验的公开来源(本站自测)
考察重点:publisher confirm 与 mandatory 返回。
相关内容:生产者确认。
参考回答
不可路由消息也可获得 publisher confirm。
mandatory=true 时,broker 会先发 basic.return。客户端需要处理路由返回,再结合发布确认判断结果。确认发布阶段也并未确认消费者业务完成。
11.3 副本数为 3,acks=all、min.insync.replicas=2 如何确认写入?
出现公司:暂无已核验的公开来源(本站自测)
考察重点:ISR 全部确认与最低同步副本数。
相关内容:生产者确认。
参考回答
ISR 有 3 个副本时,acks=all 等待这 3 个副本确认。
ISR 为 2 时等待这 2 个。ISR 只有 1 个时,低于 min.insync.replicas=2,写入失败。它以写入可用性换取最低副本保障。
11.4 Kafka 的 offset 10、12 完成而 11 未完成,能提交 13 吗?
出现公司:暂无已核验的公开来源(本站自测)
考察重点:下一读取位置与连续完成水位。
相关内容:消费者确认时机。
参考回答
应最多提交 11,让恢复从未完成的记录继续。
提交 13 会跳过 11。并行消费要逐分区追踪连续完成位置。12 在故障恢复后可再次到达,因此业务仍需幂等。
11.5 RabbitMQ quorum queue 怎样提高死信转发可靠性?
出现公司:暂无已核验的公开来源(本站自测)
考察重点:转发确认、源端保留与容量代价。
相关内容:死信转发失败。
参考回答
使用至少一次死信转发,让源队列保留消息直到目标确认。
配置 dead-letter-strategy=at-least-once 和 overflow=reject-publish,并设置 DLX 与有效路由。还需确认 stream_queue feature flag 已启用。目标故障时,未确认的消息会占用源队列容量,因此需要监控积压。
12. 参考资料
- RabbitMQ:Reliability Guide
- RabbitMQ:Consumer Acknowledgements and Publisher Confirms
- RabbitMQ:Dead Letter Exchanges
- Apache Kafka Documentation
- RabbitMQ 4.1:Confirms
- RabbitMQ 4.1:Quorum Queues
- RabbitMQ 4.1:Dead Letter Exchanges
- RabbitMQ 4.1:TTL
- Kafka 4.1:Producer Configs
- Kafka 4.1:Topic Configs
- Kafka 4.1:KafkaConsumer
- Debezium:Outbox Event Router