支付系统:根据Wikipedia的定义,支付系统是用于通过货币价值转移来结算金融交易的任何系统。这包括使其交换成为可能的机构,工具,人员,规则,程序,标准和技术。广义的支付系统形态包括:电子钱包(抖音钱包,Apple Pay / Google Pay),或者第三方支付工具(PayPal,Stripe)。
支付系统存在的挑战:
-
支持多种支付渠道:Credit Card, 微信,支付宝,PayPal等等
-
满足合规要求:如果系统要存储信用卡信息,则需要满足PCI DSS [2] 的规定
-
支持多种货币:以TikTok钱包为例,业务覆盖了南美(巴西等),中东(土耳其、迪拜等),欧洲,美国,每种国家都使用不同的货币,支付系统需要根据汇率保证交易发生的时候不会出现资损(或者说尽量减少资损)。一个Case是,土耳其因为地震导致其货币里拉大幅下跌,给我们的平台带来了巨额的资损。
-
数据一致性,支付系统最核心的内容就是保证交易数据的一致性,一旦出现问题,平台就需要承担资损。
-
反洗钱与合规:支付系统要保证平台内的资金可追溯,防止洗钱行为。
许多支付系统的核心都包含以下三个部分:
-
Pay-In:比如用户将钱充入到某个平台的账户中,比如:抖币 / TikTok Coins,或者电商平台在交易的时候会先把用户的付款打入公司的账户中,这个从用户账户到公司账户的过程叫做 PayIn。
-
Transaction:在平台中由一个账户将钱转到另一个账户的过程叫做 Transaction,比如:信用卡交易发生在Card Network中,直播间送礼发生在平台、观众、主播三个角色之间。
-
Pay-Out:资金从公司账户转移到用户账户的过程,比如:主播提现,电商平台给商家付款。
Payment Service
Compliance Service
Compliance Service is responsible for risk checking, accessing for compliance with regulations and for evidence of criminal activity such as money laundering and financing of terrorism.
Payment Executor
不是所有企业都能自己搭建一套信用卡交易系统的,因为获得支付牌照以及满足PCI-DSS的要求特别困难,所以对于一些StartUP,它们更常用的支付渠道是PayPal或者Stripe,而不会直接将信用卡的信息保存在自己的系统内。在这个Context下,Payment Executor的作用就是沟通系统内的交易活动与外部的支付渠道。
Card Schemes
Card Schemes 是支持信用卡交易的组织,世界上最大的Card Scheme:Visa,MasterCard,UnionPay(中国)
Ledger
会计层面的系统,平账用,credit + debit = 0
一个典型的pay-in过程如下:
-
用户点击"Pay",服务端创建一条支付事件 (Payment Event),并将其持久化在数据库中;
-
有时候用户可能是打包付款的,比如同时选中了多个商品合并付款,此时payment system应该将一个支付事件中每一笔付款拆分,每一个商品对应了一条支付订单 (Payment Order);
-
Payment Executor 向PSP发起支付请求
-
PSP成功处理这笔交易,并且给payment Executor返回商家获得了多少钱;
-
Wallet 服务把商家的钱更新到DB中
-
Ledger 服务把这笔交易更新到DB中
Data Model
在选择存储方案的时候,性能往往不是第一个需要考虑的要素,而是数据的准确性、一致性和持久性;可以归纳为以下三方面的要求:
-
Proven Stability:存储系统的稳定性特别重要,一个度量标准为:被一个世界顶级的大公司使用了很多年
-
Supporting Tools:Monitoring,Alarm 等
-
Maturity of Database: 存储系统必须要有专家来对系统各种问题予以支持;
通常,支付相关系统或者金融交易系统的存储方案都会选择基于ACID 事务的传统关系型数据库,而不是更加追求性能的 NoSQL / NewSQL。
Payment Event & Payment Order
一个Payment Event中可能包含了多笔Payment Order
这里需要注意的是:amount这个字段应该保存为String类型,理由如下:
-
不同的Protocol、Software、hardware 对于浮点数序列化的支持可能不同,所以如果用Number的话,有可能造成精度丢失
-
交易的金额有可能是天文数字(中国的GDP),也有可能小到极致(satoshi of bitcoin)
payment_order 表中的ledger_updated, wallet_updated, 以及payment_event 表中的status字段,应该配合定时任务使用,把未完成的交易推进到交易的最终状态。如果推进过程中出现了问题,则需要发出告警。
Design Deep Dive
PSP** Integration**
集成了PSP的交易系统流程如下:
-
用户点击 "checkout"后,客户端调用Payment 服务端,将订单信息传入服务端
-
服务端将Payment Info 包括:金额,货币,过期时间封装为 Payment请求发送给PSP,PSP使用Payment OrderID做幂等,PaymentOrderID在这里的别称为:Nounce
-
PSP 给 payment服务返回一个token,服务端可以用这个token查询一个 Payment Order 的状态,服务端会将这个token进行持久化保存
-
Token 被持久化后,客户端使用Stripe 或者 PayPal的SDK拉起收银台,让用户填入信用卡的信息;这一步额外需要两个信息:一是上一步中PSP返回的token,另一个是服务端返回给客户端一个重定向URL,当支付成功后,应该跳转到这个页面。
-
PSP 返回支付状态
-
WEB 页面跳转到重定向的URL,并且在这个页面显示支付状态。
-
PSP 会通过Payment System提供的callback URL回调我们的Payment 服务,更新支付订单的状态。
Reconciliation
在分布式系统中,每一个服务节点之间的通信都是异步的,所以任何一个网络请求都有可能延时或者永远丢失,此时就需要系统中进行对账。通常来说,对账系统是整个支付系统内保证资金正确性的最后一道屏障。
每天晚上 PSP 都会把一份 Settlement File发送到客户的支付系统中,对账系统从内部的Ledger和wallet系统中拉取当天的交易进行比对,如果对比出来了不一致,则通常需要公司的财务介入解决资金不一致的问题。
Failure Handling
每一个支付系统都必须处理出错的交易,系统的可靠性和容错性也是一个关键的设计点。
Retry Queue & Dead Letter Queue
Retry Queue:重试队列可以用来处理短暂的Error ,比如Network Error或者数据库加锁失败
Dead Letter Queue: 如果一条消息长时间得不到成功的处理,当重试次数到达上限后就会被投入死信队列
Exactly Once
支付系统中另一个重要的问题是保证一个交易不会进行两次,即:不会重复扣款,也不会重复打款,将支付系统的接口设计为Exactly Once十分重要。为了实现Exactly Once,可以考虑使用以下两个语义的合成:
-
At Least Once:通过retry使得一个事件最终被系统处理(借助MQ)
-
At Most Once:系统提供幂等的接口,保证同一个请求不会被处理两次
幂等:通常都是借助幂等Key (Idempotence Key) 加上MySQL提供的Unique Constraint 实现。
一致性保证
Wrap Up
本篇介绍了支付系统的 pay-in 和 pay-out流程,并了解了支付系统中一些常见的技术手段:retry、幂等、consistency、Error Handling、Security。
支付系统是一个极其复杂的系统,还有除了以上topic,还有一些其他问题需要考虑:
-
监控:CPU使用率,Payment 成功率,支付延迟,系统吞吐量,数据库主从同步等
-
报警:异常发生的时候及时产生报警。
-
Debugging Tools:"Why does payment fail?" -- 是支付系统经常面临并需要解决的问题,开发一个工具用来查看交易的状态,执行历史 (Processing Server History)和PSP Records
-
汇率换算:如果用户分布在不同的国家,则需要考虑汇率换算的问题
-
Cash Payment:一些国家的在线支付业务不是很发达,如:印度、巴西,所以平台需要支持 Cash Payment
-
GP/AP集成
Reference
[1] Books, an immutable double-entry accounting database service
[2] PCI DSS (Payment Card Industry Data Security Standard)
[3] 3D Secure Card authentication and 3D Secure
[4] Kafka Dead Letter Queue: developer.confluent.io
[5] Uber's Streaming Payment System
[6] Re-Architecting Cash and Digital Wallet Payments for India with Uber Engineering