如何防止系统双倍收费?
今天我们来聊一下任何跟钱相关的系统 (支付、银行、券商等) 都会面临的问题 - 双倍收费 (Double Charge)。 这个问题发生的概率可能比你想象得要高。而且由此带来的业务影响是很大的。
我们在设计系统时,必须保证系统能满足“正好一次”的语义 (Exactly-Once Semantics)。
我们把问题分成两部分,解决起来就容易多了。从数学上讲,如果满足以下条件,操作就会被准确执行一次:
-
至少执行一次 (At Least Once) 使用重试机制 (retry) 来保证。 -
同时,它最多被执行一次 (At Most Once) 使用幂等机制 (idempotency) 来保证。
重试
有时,由于网络错误或超时,我们需要重试付款交易。例如,如下图所示,客户端尝试支付 10 元,但由于网络连接不畅,支付一直失败。考虑到网络状况可能会好转,客户端重试了该请求,最终在第四次尝试时支付成功。
幂等
从API的角度来看,幂等意味着客户端可以重复进行相同的调用并产生相同的结果。 为了实现幂等,客户端会生成一个唯一ID用来代表一个请求。Stripe 和 PayPal 等许多支付公司推荐使用 UUID 作为临时ID。我们可以在HTTP头中加入这个唯一ID: <idempotency-key: key_value>
当然,作为一个完整的生产环境系统,仅仅使用重试+幂等是不够的,我们还需要加上对账系统进行事后的及时纠错。
你遇到过双倍收费的生产事故吗?欢迎留言分享
【关注公众号:ByteByteGo】