B站搜“国外大佬教你如何设计支付系统”有视频版本。
视频出处 https://www.youtube.com/watch?v=olfaBgJrUBI
目录
保证交易完成(Guarantee Transaction Completion)
利用分布式系统(making use of distributed system)
静态数据和传输中数据加密(Encryption for Data at Rest and In-Transit)
数据完整性监控(Data Integrity Monitoring)
先给个总结,主要包括如下内容。
本视频揭秘实现一个可靠和可扩展的支付系统的过程。
支付系统如何工作的?
客户去商户网站下单,客户需要提供 payment information。
网站弹出一个payment form 页面,该页面一般由 payment Gateway提供。通常payment gateway需要符合PCI-DSS ,GDPR 规则。payment Gateway通常包含其它功能进行高级检查,如:risk check , fraud prevention。所以payment gateway的主要功能就是校验financial credentials,并将其转移到 merchant bank account。
持卡人的信息被传到了 acquiring bank。acquiring bank是替商户处理card payment的银行。此时PSP - Payment Service Provider就形成了。PSP是个广泛的术语,是第三方公司帮助企业,安全可靠的促进支付业务。PSP通常提供risk management,reconciliation tools 甚至包括order management。PSP通常也可以是acquiring bank,但不是必须的。
acquiring bank 获取交易信息,执行基本校验,根据合适的card networks 路由request到持卡人的 issuing bank来获取批准。
最后客户银行 issuing bank,检查交易信息,余额,信誉良好(in the good standing),给出通过/拒绝交易响应。响应沿着原路返回到商户网站。
两种方式来建立一个支付系统
常用方式是使用PSP(如Stripe or PayPal),一般用于在线商店。简单理解PSP就是把钱从买家转到卖家。
另一种是直连银行或Card Schemes (Visa/Mastercard),这种方式不常见,且困难。
而且要遵守一些标准和法规。而且这些法规每个国家还不一样。
所以很多大公司也都选择PSP
使用PSP,我们不需要存储银行卡号到数据库中,这些都由PSP完成。
payment system会和许多内外部的服务交互,所以无法避免系统出错,而导致的不一致的状态。
因此需要对失败的交易进行修复(reconciliation )
可靠的支付系统的需求
本视频更多关注技术层面。
支付系统的组件
假设我们要给一个在线商店建立一个支付系统。至少需要下面四个部分。
用户在下单时,后台生成一个payment event发送到payment service,payment service存储payment event到数据库,调用外部的PSP。调用PSP时至少要传递amount 和 currency两个参数。
通常这些参数来自下单页面。这时,用户会看到支付页面。页面包括 payment details。
通常有两种方式提供这个页面。
1,PSP提供的form page
2,自己构建(build it in-house),这种不实际也不常见。 而且要自己存储敏感信息,同时也是非常乏味的工作。通常要符合完整的规定(compliance regulation)也不现实。除非你是特别大的公司。
所以一般用的是第一种。
PSP的工作是发送card details 到 banks 或 card scheme(visa/ mastercard)
在PSP成功处理payment后,相关的service update 钱包 wallet,钱包用于跟踪商户账户余额。wallet的数据存放在数据库。payment service 记笔账到 Ledger,Ledger主要用于财务数据分析,支持审计工作等。ledger 记录存放在数据库中。
同步和异步通信的选择
支付系统中任何所涉及的服务都有可能随时处于停止状态。
同步通信 不合适对方服务器停机,网络延迟很大的场景。而且会引起 级联失败(cascading failure),一个服务停机,整个系统就不能工作。也就是所谓的紧耦合(tight coupling)。
然而有些场景非同步通信不可。
而其它并非同步不可的情况,优先考虑异步通信。也就是所谓的松耦合(loosely coupled)。
同时异步通信在处理不均匀流量(uneven)和流量暴增(spike)等情况时,变得容易的多。可以利用持久队列(persistent queue),比如 kafka,作为一个缓冲。
据统计70%的银行和金融机构 使用kafka。
总之,异步通信适合于绝大多数情况,如 payment 欺诈检测和分析。
保证交易完成(Guarantee Transaction Completion)
如何保证在不同服务之间传递的request messages不会丢失?
或者如果保证这些messages 被收到了呢?
这时,我们可以使用message queue,如 kafka。对任何order placed 或 paid,我们都可以创建一个 kafka event。kafka会持久化messages, 所以不存在丢失message的情况。
当然kafka也有可能不可用,但几率小至 99.999%
然后这些msg可被不同的consumer各自消费。consumers 只会在msg 被成功处理,并存储在数据库后,才通知kafka,消息被消费了。
因此,这种模式可以承诺msg被成功交付给其它服务。
处理失败的payment
如何处理即时错误(Transient errors)
对于有些services之间的同步调用,显然不适合 msg queue方式。那如何处理这种同步调用时的异常情况?
下图列出了一些常见方式。
retry 需考虑 retry的次数,和间隔。
推荐使用 间隔指数级的增长的方式。
同时也要考虑多服务同时retry的情况,若间隔一致,造成目标服务器访问量剧增。
解决这种问题,在retry时候,加如随机数。
超时时间的设置问题,想象用户在下单时,设置的太短,用户看到订单超时。
但是在后端存在几种可能。
1,后端实际处理成功,但是请求超时。
2,后端还在处理中,但请求超时。
3,后端根本就没收到请求。
这时候,如何展示合适的结果给用户。
若展示失败,用户可能会在次发起支付。这里就存在重复扣款的问题。
可参考这篇文章:
Payment-ByteByteGo - How to avoid double payment? 避免重复交易-优快云博客
不过此时,我们可以在后台进行retry。
那么超时时间改设置多大?
大到可以满足最慢的服务返回,小到可以防止永不返回到服务。(😂😂😂)
备选方案的考虑 (fallback pattern)
在服务调用过程中,返回结果无法返回时,我们应该做两手准备。把对用户的影响降到最小。
比如,在payment service调用 fraud-check service过程中,出现异常,无法得到fraud check结果。这时候可以进入备用方案,例如一些常规的规则(金额的判断等)。
处理持续性的异常(persistent failures)
对于持续数分钟,甚至数小时的错误。retry也无济于事。这种情况只能取消交易。
然而,在一些系统中,持续性报错的原因可能是因为格式不匹配,导致解析response时出错,这种情况可以把 response保存起来,后续在debug - retry。
比如可以存入特定的msg queue, 这也就是死信队列(Dead Letter Queue)。
对于可以因为目标服务器暂时不能相应的情况,也可以把这些失败的调用,存入正常流程的queue。待后续重发。
重复支付问题
直接参考这篇文章 : Payment-ByteByteGo - How to avoid double payment? 避免重复交易-优快云博客
利用分布式系统(making use of distributed system)
主要是解决单体应用无法满足需求,以及各种分布式问题。可看视频或跳过参考别的文章。
静态数据和传输中数据加密(Encryption for Data at Rest and In-Transit)
静态数据加密,可在数据库或通过软件对磁盘加密完成。
对于数据传输过程中的加密可以在OSI模型的多个层实现。
VPN对网络加密
TLS提供数据加密的完整性和身份验证。TLS 不是 SSL(后者废弃与2011年)。
HTTPS用于应用层。
这些方式有不同的使用范围和场景。
其次是用户的权限控制。
然后,就是即时更新系统和软件。
接着是定期 备份数据。防止数据被破坏。
最后是 用户密码的强化,不要使用一些容易猜到的密码。。。😂 (密码方式还会用多久?)
数据完整性监控(Data Integrity Monitoring)
通过checksum方式来校验数据完整性。但是太占CPU。
而易受攻击的数据和文件包括这些内容。