消费者偶尔重复处理同一条支付消息,为什么会重复?业务幂等怎么做?
我的判断
Kafka 的常见交付语义允许重复,消费端要用稳定事件 ID 和业务唯一约束,让同一支付消息多次到达只产生一次结果。
重复通常来自业务处理成功后、offset 提交前进程崩溃;rebalance、超时重试和生产者重发也会造成。我们不会追求“永远不重复”,而是让副作用幂等。
支付消息会带不可变 eventId 和支付流水号。在本地事务中先插入消费记录或直接依赖业务唯一约束,再更新订单:
INSERT INTO consumed_event(event_id, consumed_at)
VALUES (?, NOW()); -- event_id UNIQUE
若唯一键冲突,说明已经处理,返回成功并提交 offset。消费记录和订单变更必须同事务,否则记了“已消费”但订单没更新会永久漏处理。
调用外部系统时会把业务幂等号传过去;对方不支持时用本地状态机与查单补偿。Redis SETNX 可以做快速挡板,但不能作为唯一证据,因为过期、淘汰和故障转移都可能失去记录。