常见的 PayPal、Stripe、支付宝、MasterCard、VISA、Apple Pay、Google Pay
支付系统是通过转移货币价值来完成金融交易的系统,包括促成交易的机构、工具、人员、规则、程序、标准和技术
支付系统,有人认为像 Apple Pay、Google Pay 之类的电子钱包,有些人认为是一个处理支付的后端系统,或支持PayPal或信用卡支付的系统。
假设:
例如顾客在亚马逊下单之后发生什么
业务事件 -> 支付系统 -> PSP 支付服务处理器
复式记账系统 Double-Entry System,它把每笔支付交易记录在两个相互独立的账户中,金额相同,一个账户借记,另一个账户就会贷记相同金额。
复式记账系统声明所有交易分录只和必须等于0,每一个账户中损失的金额,必然对应在另一个账户中获得的相同金额。提供 了端到端的可追踪性并确保了整个支付周期的一致性。
大部分公司倾向于不存储顾客的信用卡账户信息,不然就得遵守 支付卡行业数据安全标准 Payment Card Industry Data Security Standard,PCI DSS 中的所有复杂规定。
支付SDK页面 嵌套在自己应用里。
收款流程的高层级架构
亚马逊按照预先设定的频率,比如一个月一次给卖家付款的流程。
支付交易记录汇总,调度器处理每个卖家通过支付API向卖家付款。
卖家仪表板展示卖家在下一个付款周期将要收到的总金额的实时数据。
Apache Kafka 是一个发布订阅消息系统,很快,具有高可扩展性、可用性以及节点故障 的容错性,Kafka 类似于消息队列,但有几个关键区别;
因为同一个支付事件通常由多个下游服务来处理,比如 付款流程、报告流水线、数据分析服务、会计等,所以很适合 Kafka。 创建实时仪表盘通常用到 Vertica、Druid、Amazon Redshift、Google BigQuery等分析数据库,它们为数据分析专门优化过的专业数据库 对查询性能和可扩展性做了优化。
为了确保顾客只被收费一次,需要确保支付交易至少发生一次,至多也只发生一次。
重试,网络故障或超时,客户端因网络不佳重试请求,多次后终于成功。重试时间间隔很重要, 有 立即重试、固定间隔、递增间隔、指数退避、取消 很多方案。
重试可能造成的问题是重复支付,例如顾客快速点击两次支付发两次请求,PSP成功地处理了支付请求,因为网络错误,响应未能到达我们的支付系统。
幂等性是确保 至多一次 的关键。是一种在数学和计算机科学中特定操作所拥有的特性,操作可以进行多次但结果在第一次操作之后就不会再改变。
PSP 也提供这种确保这种幂等的重试操作。客户端请求幂等键到支付系统,支付系统会将支付请求记录在交易日志数据库, 支付系统通过幂等键向PSP请求,但是回调没收到,支付系统从 交易日志数据库 捞起来幂等键 重试支付,PSP 那边保证幂等性。
支付流程可以是同步的也可以是异步的。
同步的客户端、服务器通信过程,客户端发送HTTP支付请求,然后服务器支付系统通过HTTP响应返回结果。
异步的客户端、服务器通信过程,异步通信的关键组件是队列,队列和Kafka可以互换使用。
是等待响应还是把请求放入队列以便稍后再处理,需要看具体场景。
内部服务之间的同步通信,比如用 HTTP 协议。
模式存在问题:
内部服务之间的异步通信,两类 单接受者 和 多接受者:
单接受者,用 RabbitMQ 消息队列就好:
多接受者,每个请求(消息)被多个接受者或服务处理,Kafka 很管用。
简单设计是单体数据库,支付交易意味着把资金从一个账户转移到另一个账户,尽管真正的资金发生在PSP内部,但我们的支付系统也需要记录每个交易状态:包括授权、捕获、结算、入账、退款等。
对于 transaction_entry
一个交易通常包含多个交易条目,交易条目只能追加写不可变,必须存储完整的交易历史以便审计,支付出错时可以容易容易追溯哪个步骤导致了问题。
分布式数据库,单体数据库中保持数据一致性是相对简单的,但分布式数据库实现数据一致性就很有挑战性。
共识协议,比如两阶段提交 Two-phase Commit,Raft、Paxos、Saga模式等,当两个不同服务之间的状态产生分歧时,我 们希望修复状态 ,使它们保持一致 。有两种方法可以修复不一致的状态:同步修复和异步修复。
持久化保存支付状态,在支付周期的任何阶段都拥有明确的支付“状态”是至关重要的。这样,当发生故障时,我们就可以确定支付交易现在的“状态”,并决定是否需要重试或者退款 。支付“状态”可以持久化存储在一个只可追加写 的数据库表中。
重试队列和死信队列: