4. 支付链路全景

做支付链路 Tracing,第一步不是埋点,而是把链路本身拆清楚。很多团队定位交易问题慢,根本原因不是日志不够,而是对“一笔支付到底经过了哪些系统、每个系统负责什么、状态在哪里发生变化”缺少统一认知。本节把一笔支付从用户点击“提交订单”到最终账务入账、对账平账的全过程拆成七个关键环节,并给出每个环节的观测重点。

一、核心原理:支付链路是一条“状态推进链”

支付链路的本质,是一条由多个系统接力推进的状态机。用户看到的是“支付成功”或“支付失败”,而系统内部经历的是订单创建、支付单创建、渠道请求、渠道回调、账务记账、对账核销等一系列状态迁移。每一次状态迁移都对应一次跨系统调用,也都是一次可能出错的观测点。

因此,理解支付链路要抓住三个核心:单据流转(订单号、支付单号、渠道流水号如何映射)、状态流转(每个系统维护自己的状态,且必须最终一致)、资金流转(账务与对账如何确认钱真正到位)。Tracing 的价值,就是让这三条线在同一 TraceID 下可被串联还原。

支付链路全景与关键观测点 用户下单 订单号生成 收银台 支付方式选择 支付网关 支付单创建 渠道适配 协议转换 银行/三方通道 渠道流水号 账务与对账 记账/核销 关键标识映射 订单号 orderNo → 支付单号 payNo → 渠道请求号 requestNo → 渠道流水号 channelSeq → 账务流水号 ledgerNo 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 的上限。