SWE / Applied Scientist · System Design / OOD

Amazon Payment LLD:支付意图、幂等与账务事实

区分业务支付意图、渠道尝试与账务记录,处理回调重复、超时和退款。

题目重点:区分业务支付意图、渠道尝试与账务记录,处理回调重复、超时和退款。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 只有Payment Systems LLD方向,未给具体网关、币种和退款。练习定义单订单单币种支付、可重试尝试和部分退款;不承担真实监管规则设计。
  • 外部渠道可能超时但已经收款,回调可能重复/乱序。内部ledger是权威入账事实,客户端成功页面不构成结算证据。

解题路线

  1. PaymentIntent保存订单金额/币种/业务版本,Attempt保存providerRequestId与渠道状态,LedgerEntry记录不可变金额变化;用整数最小货币单位或明确Decimal,避免float。
  2. 创建intent用业务幂等键且校验重复请求参数一致;相同key换金额应冲突而非返回旧成功。外部请求用稳定渠道幂等键,内部状态通过版本CAS和事务改变。
  3. 状态pending→processing→succeeded/failed,网络超时保持unknown/reconciling;只在确认渠道失败后新建合规尝试。回调验证身份和金额,唯一providerEventId防重复,再写ledger和outbox。
  4. 账务和订单状态不能靠双写“碰巧成功”;在同事务写入ledger/outbox,由消费方幂等更新订单。退款先原子预留可退金额,再发渠道请求,成功减少预留并记退款事实,失败释放预留。

手动走一遍

100单位订单的首attempt超时:先按providerRequestId查询,不能直接再扣100。两个并发60退款请求最多一笔预留成功,否则总退120超出原款;重复退款回调不再次扣额度。

规模与取舍

主键/唯一索引操作通常O(log N),单订单总额和可退额度是串行化点;外部调用延迟不能算数据库事务复杂度。按intent分片可扩吞吐,跨币种/跨订单汇总需要清晰账本维度。

易错点与追问

容易失分的边界

  • 把timeout记failed导致重复扣款。
  • 只在应用层查询幂等键,没有数据库唯一约束。
  • 退款总额检查与预留分开,在并发下超退。

继续深挖

  • 若provider不提供幂等请求,怎样降低风险并明确无法保证的边界?
  • 如何做定期对账并修正“渠道成功内部未知”?
✓已复制微信号!