一、问题
在支付系统中,订单可能由于网络问题、用户重复点击等原因被重复提交,这样类似的问题都可能给公司带来巨大的经济损失,最近无意中看到了这个问题的讨论,故此来小作研究,希望也给大家有所参考。
二、原理
幂等性是指某个操作的重复执行不会改变最终结果。换句话说,无论这个操作执行多少次,结果都是相同的。
打个比方吧,
假设你有一把钥匙,用来打开家里的大门。无论你转动钥匙一次、两次,甚至十次,门只会在第一次转动时被打开。之后的转动不会再让门“重复打开”,因为门已经处于打开状态了。这就是一个幂等操作:不管你操作多少次,结果总是一样的——门始终是打开的。
在支付场景下,这就像确保每次打开的都是同一扇门(订单):
- 唯一标识符:门对应你的订单,每扇门都有一个特定的钥匙(订单号),系统通过订单号识别每个支付请求。
- 状态检查:在你试图“打开”门时(处理支付请求),系统会先检查门是不是已经开了(是否支付过)。如果已经开了(支付成功),它就不会再重复操作。
- 重复无害:即使你多次尝试打开这扇门(发起支付请求),最终的状态(订单支付成功)不会因为重复请求而发生变化。
三、工作方式
- 幂等操作设计
确保操作本身具有幂等性。例如,在支付订单时,支付操作的逻辑应该是幂等的,即无论调用多少次,最终结果都是相同的。 - 唯一标识符(ID)
在每个请求中包含一个唯一的标识符(如 UUID 或订单号)。在处理请求时,系统首先检查是否已经处理过该标识符。如果是,则直接返回之前的处理结果,而不是重复处理。 - 数据库锁
在数据库层面使用锁机制(如行锁、表锁)来防止同一条记录被同时处理。这样,即使多个请求同时到达,只有一个请求会被处理,其他请求会被阻塞或返回错误。 - 重复提交检测
在服务器端维护一个状态表(如 Redis 缓存或数据库表),记录已经处理过的请求的唯一标识符和状态。当收到新的请求时,首先检查该标识符是否存在于状态表中。如果存在,则说明该请求已处理过,直接返回结果。 - 幂等性中间件
使用中间件来处理幂等性。例如,在微服务架构中,可以使用 API 网关或中间件来检查和保证请求的幂等性。
四、示例
假设我们有一个支付订单的接口,它接收订单请求并处理支付:
1、请求处理逻辑:
接收请求时,检查请求中是否包含唯一标识符。
查询数据库或缓存,检查该标识符是否已经处理过。
如果已经处理过,直接返回结果;如果未处理,执行支付操作,并记录该标识符及处理状态。
2、唯一标识符的生成:
客户端生成一个唯一的标识符,并将其包含在请求中。这个标识符可以是 UUID、订单号或其他唯一值。
3、幂等性状态存储:
使用 Redis、数据库表或其他存储介质,记录每个唯一标识符的处理状态(如已处理、未处理)。
==============================================================
重复支付最经典也最常说的解决方法就是幂等数,但其实根据不同情景下的业务还有更合适的其他方法,日后结合具体场景再慢慢研究吧。
原创码字不易,希望大家多多支持,点赞、收藏、评论、关注我吧😄