连支付宝都崩了,还开猿节流吗?
大家好,我是程序员面试刷题平台的鸭鸭!
双十一一早,鸭鸭来到熟悉的早餐摊,准备买个早餐去上班。
但鸭鸭万万没想到,连付了三次,都没成功,银行卡里的钱倒是扣了,但界面仍显示支付失败。
鸭鸭打开手机一搜,原来受害者还不止鸭鸭一个人。
除了支付失败外,鸭鸭还看到余额宝提现未到账、花呗还款扣款成功但账单没清的情况。这一故障平等地影响了安卓和 iOS 系统的用户:大家都付不了款,商家也收不到钱。
找客服也不行,人工客服一直显示连接失败:
没想到啊没想到!今年真的是啥软件都崩过(真就开猿节流了吗?),竟然连支付宝也没逃过!
而且此次故障时间应该有一个小时左右。不知道大家有没有听过高可用性即 SLA。
高可用性是一个 IT 术语,指系统无中断地执行其功能的能力,代表系统的可用性程度。是进行系统设计时的准则之一。
一般系统要求至少达到 4 个 9,大厂系统特别是金融相关那要求就更高,需要 5 个 9 甚至 6 个 9 !
啧啧,不知道昨天这个锅又会甩到哪位天选打工人的身上。鸭鸭为 TA 默哀一下。
昨天 11 点 25 分支付宝也发出的公告,截止昨天上午 10 点 50 分,支付宝才修复这个故障,并表示该故障不会影响用户的资金安全。
确实,在公告发出来不久后,坐在办公室的鸭鸭收到了早上误扣的退款信息。
还好没耽误中午干饭。侧面也说明虽然高可用没做好,但是兜底策略做的还是不错的,至少保证了数据的最终一致性!
后续鸭鸭在面试鸭上再补充对应的场景面试题,防止小伙伴们被面试官问:“上次支付宝挂了你知道吧?请问你觉得是哪一步出了问题?”
好了,该看今天的面试题了,今天也给大家带来一道场景题。
一笔订单,在取消的那一刻用户刚好付款了,怎么办?
回答重点
这种情况在正常的业务场景中是有可能出现的,因为订单都会有定时取消的逻辑,比如 10 分钟或者 15分钟,而用户刚好卡在这个时间点进行付款,此时就会出现两种情况:
1)用户支付成功,支付回调的那一刻支付单刚好还没取消,而等回调结束,取消支付单的事务提交,支付单取消。此时用户扣款了,但是对应的权益或资产没了。
2)用户支付成功,支付回调的那一刻支付单已经被取消。但此时用户已经扣款,东西却没了。
可以看到,不论是哪种情况,其实都需要做一定的处理,不然用户肯定会来投诉!
这种场景无非就是支付单支付成功和取消两种状态的“争夺”,正常情况下,订单或者支付单都会有状态机的存在,在当前场景简单来说有以下两条路径:
1)待支付->支付中->支付成功
2)待支付->支付中->已取消
针对情况 1 ,如果是支付回调取胜,此时的状态应该已从 支付中->支付成功 针对情况 2 ,如果是取消支付单取胜,此时的状态应该已从 支付中->已取消
所以我们在修改支付单状态的时候,基于原始状态的判断,就可以做正常的处理,来看下 SQL 应该就很清晰了:
# 支付成功
update pay_info set status = 'paySuccess' where orderNo = '1' and status = 'paying';
# 取消
update pay_info set status = 'cancel' where orderNo = '1' and status = 'paying';
重点就是我们加了 status = 'paying'
这个条件,这就能保证个情况只有一个能成功,另一个一定失败。
1)假设情况 1 成功了,此时用户已经成功付款,那么 status 已经变为 paySuccess,取消的 SQL 必定执行失败,此时就让它失败,不需要做任何别的处理。
2)假设情况 2 成功了,此时订单已被取消,status 已经变为 cancel,支付成功的 SQL 必定执行失败,这种情况下我们就需要做逆向处理,即给用户退款 。订单被取消,用户的钱也被原路退回,这种处理也没任何问题。
业务小优化
针对订单超时业务,这里在业务上可以做一个小优化,你想想,用户付款前可能有点挣扎,然后在最后一刻终于下定决心进行付款,这时候却告知被退款了,用户很可能就不会再下单了。因此我们在页面上可以限时订单取消倒计时为 10 分钟,但实际后端是延迟 11 分钟取消订单,这样就能避免这种情况的发生啦。
Redis 分布式锁实现
最后除了利用数据库处理,还可以使用分布式锁,对一笔订单加锁也能保证这笔订单正常的业务流转。
每次进行取消订单或付款操作时,首先尝试获取订单的分布式锁,确保只有一个操作能修改订单状态。
在分布式系统中,订单在取消的同时用户付款的竞态问题可以通过分布式锁来解决。以下是一个具体的、落地的方案,确保订单状态的可靠性,避免因并发导致状态冲突:
订单取消流程:
1)超时触发取消订单
2)取消订单方法中先获取该订单的分布式锁。如果锁被其他操作持有(如付款),等待或抛出异常。
若成功获取锁,检查订单状态是否已付款:
- 若订单未付款,将订单状态更新为“已取消”。
- 若订单已付款,直接跳过这笔订单的处理。
- 释放分布式锁,完成取消流程。
订单付款流程:
1)三方支付成功回调。
2)后端系统接收回调后,先获取该订单的分布式锁,如果锁被其他操作持有(如取消),等待或抛出异常(没有给三方响应成功,三方会重新发起回调)。
若成功获取锁,检查订单状态是否为“待支付”:
- 若订单状态为“待支付”,继续执行扣款,并将订单状态更新为“已付款”。
- 若订单状态为“已取消”,则发起退款,并提示用户订单已取消,无法支付。
- 释放分布式锁,完成流程。
扩展知识(点击小程序即可查看答案)
-
- 分布式锁一般都怎样实现?
原文地址:https://blog.csdn.net/codenav/article/details/143745872
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!