ThisAI 的支付系统有何特别?
平台
其实做支付系统,最先要考虑的就是以下问题:
• 做哪些平台?
• 有哪些板块?
• 在哪些设备?
ThisAI首选的平台是微信和支付宝。
众所周知,业界内的微信是公认的一朵奇葩,不给sandbox环境,文档晦涩难懂。但是网上有太多太多的教程,也有成熟的各种语言库,开发难度总体不太难。
微信支付
微信支付和微信公众号特别相似,因为ThisAI主要点在PC,所以这里只做了H5
支付宝支付
Alipay和微信支付比较类似,除开部分细节,大致一致。
板块
ThisAI要做的板块非常简单,就只是优惠券+支付,但就这两个板块也花了我们不少时间。第一是团队内的人都没有太多经验,其次是因为文档(真的很难读懂,而且更新不及时)。
设备
ThisAI在PC上由用户扫码完成支付,在移动端则不做支付功能,以此规避部分问题。
细节
说完了这些,聊聊细节问题。
Timer
计时器可以说是一个非常重大的问题,因为不同设备、不同环境、不同浏览器策略都不一致,要考虑到各种时间精度,还需要考虑到用户的时区问题,尤其是用户手动修改时区导致的回流。
ThisAI的支付系统将所有计算全部放在了服务器,只给客户端具体的信息,客户端只负责展示,甚至不包括部分渲染。
举个例子,生成订单的一瞬间,服务端会统一QuotaSnowFlakeTime去做start和end的匹配
const orderId = genId();
const time = genTime();
// Using RFC format to adapt WeChat and also have ISO UTF addon.
在上段代码中,time使用RFC的时间格式,海桐了ISO UTF的格式,以此避免时区同步问题。
const [start, end] = time.stamp
ThisAI使用时间戳做倒计时展示,准确来讲:
• 避免浏览器最小化的时候因为计时器不准确导致的倒计时不准确,因此会提供CreatedTimeStamp做倒计时同步。
• 客户端展示的时候会考虑监听WindowsTabVisible去做时间格式化处理,并且做好time-diff的展示。
• 为了规避setInterval的不确定性,使用set timeout做最后的抉择。
• 由于
requestAnimationFrame会存在离屏渲染问题,提供了timer的全局统一计时。• 考虑到频次问题,过快的fetch status或者过慢都会导致用户体验不加,因此考虑做时间分段。用户发起支付时一般会倾向于在1分钟内做完支付,越往后支付可能性越小,因此支付系统的频率将会根据时间逐渐降低。
• 用户刷新页面时会重新fetch接口,后端需要重新根据参数做缓存处理,提供订单近况接口,返回5分钟以内的订单,后端做了消费队列轮训,自动扫描队列处理未处理的订单,扫描的时候会顺带更新redis的相关数据,所以获取到的一定是最新(指信息同步最新)最近(指时间维度最小)的订单,可以通过这个接口来查询订单状态(支付后)或者判断支付订单倒计时。
Callback
回调三方也是一个重要的问题,支付完毕后需要不断接受第三方平台的回调通知。
最初,ThisAI使用的是回调查询缓存再查询表方案,后续发现缓存这一块可能会存在消费队列更新的情况,会导致数据不同步,因此回调会直接打到数据库。
可能部分读者会认为直接打到数据库会不会存在压力,实际情况时MySQL的优化远比你想象中要好,并且我们做了降级处理,当支付流量过高时会直接存入队列,如果完全无法处理会直接拒绝调第三方回调。原因如下:
• 存入队列后可以缓慢消费,但由于支付系统时一个实时性特别高的方案,所以此时会先标明支付完成,但是不派发奖励,处理后再做奖励处理。(此时只需要一个redis字段即可实现)
• 流量过高导致潜在的雪崩时,由于第三方会存在备选的回调,由第三方帮我们做负载均衡。
其实做制作的时候会遇到挺多问题,不过一定要相信自己的代码是没问题的,多去看看文档的细节,会发现很多时候漏掉了一个小部分。不过,第三方的接口变动但是文档没更新这种情况其实普遍发生,所以建议还是使用成熟的类库。
由于篇幅有限,笔者就暂时分享到这里,感兴趣的可以评论一下,后续会分享更多相关资讯。

