自学内容网 自学内容网

连支付宝都崩了,还开猿节流吗?

大家好,我是程序员面试刷题平台的鸭鸭!

双十一一早,鸭鸭来到熟悉的早餐摊,准备买个早餐去上班。

但鸭鸭万万没想到,连付了三次,都没成功,银行卡里的钱倒是扣了,但界面仍显示支付失败。

鸭鸭打开手机一搜,原来受害者还不止鸭鸭一个人。

除了支付失败外,鸭鸭还看到余额宝提现未到账、花呗还款扣款成功但账单没清的情况。这一故障平等地影响了安卓和 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)后端系统接收回调后,先获取该订单的分布式锁,如果锁被其他操作持有(如取消),等待或抛出异常(没有给三方响应成功,三方会重新发起回调)。

若成功获取锁,检查订单状态是否为“待支付”:

  • 若订单状态为“待支付”,继续执行扣款,并将订单状态更新为“已付款”。
  • 若订单状态为“已取消”,则发起退款,并提示用户订单已取消,无法支付。
  • 释放分布式锁,完成流程。

扩展知识(点击小程序即可查看答案)

    1. 分布式锁一般都怎样实现?

原文地址:https://blog.csdn.net/codenav/article/details/143745872

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!