分布式事务重试幂等控制:网络抖动导致重复扣款?业务流水号 + 状态机拦截!
公司的支付系统出了个大事故。一笔订单因为网络抖动,支付回调超时了,系统重试了扣款。结果扣了两笔——用户投诉,财务对账发现了差异,运营逐笔人工退款。查日志发现,不是网络不通,是"半通"——第一次扣款请求发出去了,银联处理成功了,但响应在回来的路上丢了。系统认为扣款失败,又发了一次。 这种"网络半通"是分布式系统里最危险的情况——操作已经执行了,但调用方不知道。不加重试怕丢,加多了怕重。今天聊聊怎么用业务流水号加状态机,让重试在"安全"的边界内进行。 问题的本质:操作不是天然幂等的 HTTP 的 POST 不是幂等的,数据库的 INSERT 不是幂等的,银行的扣款接口更不是幂等的。如果不做任何处理,同一个扣款请求发两次,钱就会扣两笔。 分布式系统里有太多场景需要重试——网络抖动、超时、服务暂时不可用。重试本身是合理的,问题在于你拿什么来判断"这次重试的请求,上一次有没有已经成功过了"。 答案就是业务流水号。不是数据库自增 ID,不是 UUID,而是一个由业务方生成、全链路唯一、可用来判断"这条请求我见没见过"的标识。 业务流水号:请求的唯一身份证 业务流水号的核心原则:由发起方生成,....