直接回答:严格意义的端到端 exactly-once 在分布式系统里无法实现(两军问题的变体——发送方无法区分“消息丢了”与“确认丢了”,重试必然带来重复可能)。现实可行的是“effectively-once”:at-least-once 投递 + 幂等消费 + 事务性产出。Kafka 的 exactly-once 语义实质是把 offset 提交与消息生产放进同一事务,保证“读-处理-写”链条在 Kafka 域内恰好一次,出域(写外部 DB、调第三方)仍要自己做幂等。
展开解析:逼近手段按层落:生产端幂等(producer 带 PID+序列号,Broker 去重同分区重试)与事务(跨分区原子写);消费端是主战场——把消息唯一键(业务 ID 或 topic+partition+offset)作为幂等键,消费结果与去重记录放同一本地事务(DB 唯一约束兜底);涉及状态变更用版本号/CAS 或状态机(已终态的订单拒绝重复流转)。常见失效场景:消费成功后提交 offset 前宕机导致重放(所以处理必须可重入)、外部副作用(发短信、扣款)无法回滚需业务补偿、去重表无限膨胀要 TTL 与归档。面试加分:指出“精确一次”的宣传边界,能画出故障时间线(哪一步宕机会重放、幂等在哪一环兜住);并给出观测手段——重复率监控(幂等键冲突计数)、积压与重试队列告警,证明你的方案真的在工作而不是理论上成立。
追问方向:去重表设计要注意什么?跨系统副作用如何纳入 effectively-once?
(约 490 字)