4. 支付链路全景
做支付链路 Tracing,第一步不是埋点,而是把链路本身拆清楚。很多团队定位交易问题慢,根本原因不是日志不够,而是对“一笔支付到底经过了哪些系统、每个系统负责什么、状态在哪里发生变化”缺少统一认知。本节把一笔支付从用户点击“提交订单”到最终账务入账、对账平账的全过程拆成七个关键环节,并给出每个环节的观测重点。
一、核心原理:支付链路是一条“状态推进链”
支付链路的本质,是一条由多个系统接力推进的状态机。用户看到的是“支付成功”或“支付失败”,而系统内部经历的是订单创建、支付单创建、渠道请求、渠道回调、账务记账、对账核销等一系列状态迁移。每一次状态迁移都对应一次跨系统调用,也都是一次可能出错的观测点。
因此,理解支付链路要抓住三个核心:单据流转(订单号、支付单号、渠道流水号如何映射)、状态流转(每个系统维护自己的状态,且必须最终一致)、资金流转(账务与对账如何确认钱真正到位)。Tracing 的价值,就是让这三条线在同一 TraceID 下可被串联还原。
二、方法流程:七个环节的职责与观测重点
下面按链路顺序拆解每个环节的职责、关键动作和 Tracing 观测点。
| 环节 | 核心职责 | 关键单据/状态 | Tracing 观测重点 |
|---|---|---|---|
| 用户下单 | 创建业务订单,锁定商品与金额 | orderNo、订单状态 | 下单耗时、幂等键、金额校验 |
| 收银台 | 展示支付方式,发起支付请求 | 支付方式、支付参数 | 用户行为埋点、支付方式可用性 |
| 支付网关 | 创建支付单,路由到渠道 | payNo、支付状态 | 路由规则、支付单幂等、状态机 |
| 渠道适配 | 协议转换、签名、加解密 | requestNo、渠道参数 | 签名失败、超时、报文日志 |
| 银行/三方通道 | 实际扣款,返回渠道流水 | channelSeq、渠道状态 | 渠道响应码、耗时、异步通知 |
| 账务 | 记账、更新账户余额 | ledgerNo、账务状态 | 记账幂等、借贷平衡、时序 |
| 对账 | 渠道账单与本地账单核对 | 对账批次、差异单 | 差异类型、处理时效、核销结果 |
三、案例场景:一笔微信支付的全链路还原
假设用户在电商 App 下单,选择微信支付,支付 199 元。我们用一段简化的日志串联来还原链路。
TraceID: tr-8f3a2c91
[order-service] orderNo=O20240612001 amount=19900 status=CREATED
[cashier] payMethod=WECHAT_PAY payNo=P20240612001 status=INIT
[pay-gateway] route=WECHAT channel=wechat_v3 requestNo=R20240612001
[channel-adapter] sign=OK reqTime=2024-06-12T10:00:01.230
[wechat] prepay_id=wx12100001... return_code=SUCCESS
[pay-gateway] status=PAYING wait_callback=true
[wechat-callback] channelSeq=420000123420240612 status=SUCCESS
[pay-gateway] status=SUCCESS notify_order=true
[ledger] ledgerNo=L20240612001 debit=19900 credit=19900 status=POSTED
[recon] batch=20240612 channel=WECHAT result=MATCHED
从这段日志可以看到,TraceID 贯穿了订单、收银台、网关、适配、渠道、账务和对账。但真正定位问题时,仅靠 TraceID 不够,还需要把 orderNo、payNo、requestNo、channelSeq、ledgerNo 的映射关系记录下来。例如渠道回调只带 channelSeq,网关必须能通过 requestNo 反查到 payNo,再关联到 orderNo。
实战建议:在支付网关的支付单表中,至少冗余存储 orderNo、requestNo、channelSeq 三个字段,并建立索引。这样无论从哪个单据号进入,都能在 1 次查询内还原全链路。
四、误区与复盘:链路拆解中最容易踩的坑
- 误区一:只关注同步链路,忽略异步回调。很多支付问题发生在回调阶段,如回调丢失、重复回调、乱序回调。Tracing 必须覆盖回调入口,并记录回调报文与处理结果。
- 误区二:认为 TraceID 能解决一切。TraceID 在跨系统传递时可能丢失,尤其是渠道回调、消息队列、定时任务场景。需要在每个系统内部记录本地单据号,并支持反查。
- 误区三:把账务和对账当成独立系统。账务与对账是支付链路的最终确认环节,必须与支付单状态联动。例如支付成功但账务未记账,属于典型的“单边账”,需要告警和补偿。
- 误区四:状态机设计过于简单。支付状态至少应包含 INIT、PAYING、SUCCESS、FAIL、CLOSED、REFUNDING、REFUNDED 等,且状态迁移必须幂等、可追溯。
复盘要点:每次支付故障后,除了修复问题,还要检查链路拆解是否完整。如果某个环节没有日志、没有单据映射、没有状态记录,那么下次同类问题依然无法快速定位。链路拆解的完整性,直接决定 Tracing 的上限。