最近某披萨品牌与知名游戏的联动再次冲上热搜,只不过原因是许多用户在支付过程中遇到问题,出现长时间无法支付,重复支付等异常情况。本文想要从一般的秒杀及支付系统的设计方面探讨一下故障出现的可能原因,以及预防方案,最后聊一聊区块链在这方面的解决方案。由于作者并不了解本次故障具体的技术细节,所以文中可能包含大量的主观推测,还请读者见谅。
流程复盘
活动开始当日上午9点,披萨APP上开启活动产品的预约,不久,产品就已售罄。同时,社交网络上开始出现“披萨APP崩溃“的用户反馈。主要反馈的问题有:
- 订单已经支付,但是显示支付未完成
- 一份订单支付成功两次
- 订单无法支付(提示网络异常)
在大量用户反馈问题之后,披萨品牌表示会将订单的可支付时间由半小时延长到24小时。
问题分析
本次活动的主要步骤可以分解为:1. 创建订单;2.支付订单。
在创建订单这一步是没有出现用户反馈问题的,尽管同时抢购的用户数量很多,但是一般只需要合理地将用户进行分区,例如,假设产品限量10万份,可以创建10个并行的服务,每个服务上放置预先生成的1万份产品编码,我们这里用 token 来表示。然后使用哈希将用户分流到这10个服务上。每个服务就只需要维护1万 token 的集合。
主要问题是在支付订单这一步,首先,只有获得 token 的用户才有资格进行支付。那么当服务器拿到用户发来的 token 的时候,需要做以下工作:1. 验证此token是否是真实的;2. 验证此token是否过期;3. 验证此token是否被使用过。
第一步是比较简单的,可以使用数字签名技术来验证,比如每个 token 都是有商家私钥签名的。第二步也很简单,token内的时间戳和当前的时间对比一下,就知道有没有过期。真正复杂的是第三步,我们刚才提到了,总共有 10 万份产品,那么至少就有 10 万个 token,且它们一直在更新(每时每刻都有订单支付成功,支付成功,token 失效)。这意味着这一步是无法并行的,一旦并行,就有可能出现双花 ———— 一个 token 被使用两次。
这一步里极大的串行任务的堆积,有可能是导致服务崩溃的主要原因。
另外,有用户表示同一笔订单支付了两次,这是因为大多数用户使用的是第三方支付服务,在“支付成功->token失效“这个过程中,如果中间断开了,就可能导致支付两次。
解决方案
首先我们探讨一下在业务层面的解决方案,可以采用预付订金的机制,比如,在活动开始前的一周里,用户可以预付订金参与抽签,活动开始当日公布抽签结果,未中签的用户自动退还订金。将支付的任务分散开来。
如果不想改变业务逻辑,我们还可以在 token 上做文章,比如,将全部 token 分为 n 组,并在 token 上标注分组编号;同时启用 n 个验证服务,每个服务只负责维护对应分组的 token 集合,相当于把串行任务分为了 n 个并行任务。
区块链的应用
根据白皮书 "A Peer-to-Peer Electronic Cash System" 实现的区块链系统理论上是可以无限扩容的,并且由其特有的工作量证明(POW)机制,能够超越分布式系统不可能三角(CAP),有效解决支付过程中的双花问题。
这里我们尝试设计一个运用区块链系统的解决方案。首先,商家发行10万个 token,每个 token 是一个 UTXO(未花费输出),其中包含的金额可以是 1 聪(区块链上最小的金额单位)。
另外,我们需要第三方支付也支持这一区块链系统,例如现在的数字人民币系统。
在用户获得了 token,进行支付的时候,用户将发起一笔区块链交易,这笔交易的会消耗 token,并向商家支付对应的金额。当商家从区块链的“交易处理商”(俗称矿工)那里了解到这笔交易已经有极大概率成功 ———— 这个过程只理论上不到1秒钟,实际取决于区块链系统中矿工的网络状况 ———— 就可以认为这个token已经失效,且支付已成功,这是一个原子操作。
如果交易不成功,那么token不失效,且支付不会成功。
结语
以上,是作者对某披萨品牌这次联动事故的简单分析,和尝试提出的解决方案。我们相信在现有的网络服务技术下,是有可能实现此类大型活动的。而在采用一些新技术,例如区块链,则有机会大大降低硬件成本和操作难度。本文乃作者一家之言,如有错误之处,请不吝赐教。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。