Skip to content

支付对账:流水采集、差异识别与补偿 ​

支付回调负责及时更新业务,对账负责发现遗漏和不一致。对账可以由渠道账单可用事件触发,也可以定期拉取;用户登录不应影响它是否执行。

示例按商户、渠道、币种和业务日期建立对账批次。具体账单生成时间、时区与字段以支付渠道约定为准,不把“每天 00:00”假定为所有渠道账单都已完整可用。

从回调处理推导独立对账 ​

假设用户付款后,支付回调通常能及时到达。回调适合更新当前订单,却不能证明历史上没有漏接事件;反过来,每次用户查看订单都完整拉一遍渠道账单,也不能形成稳定的核对范围。

候选方案能提供什么无法单独证明什么
只处理支付回调及时接续业务变化某段历史是否漏了事件
定期查询未完成订单修复已知待支付对象本地根本没有对应记录的渠道交易
完整采集窗口后双向匹配对指定范围建立可复查证据仍需界定渠道数据是否完整及允许延迟

本篇保留回调的实时路径,再按明确范围做独立对账。原始采集、匹配和补偿分开,是因为“不一致尚待确认”与“已经可以执行修复”具有不同的证据要求。

采集、匹配与复核时序 ​

渠道请求位于数据库事务之外。只有输入完整性满足要求,后续匹配才有依据判断两侧差异。

任意一页失败时,循环暂停在已提交检查点,不能继续把缺失页当成渠道没有对应交易。补偿是另一个可追踪的业务动作。

对账需求与完成标准 ​

示例分为“完整采集渠道事实”“匹配本地流水”“确认差异”“按规则补偿”四个阶段。采集完成不等于差异已解决,对账成功也不表示自动执行了资金操作。

决策示例约定开发约束
对账范围商户、渠道、账户、币种和固定窗口不跨账户混用流水身份
数据完整性账单可用,所有分页成功保存未完成采集不判定单边缺失
复核等待为渠道延迟保留明确复查窗口未确认与已确认差异分开
自动补偿范围仅执行明确批准的幂等补记规则资金动作走独立权限与审核
业务完成差异有可追踪的解决结果或待办不用“任务已运行”代替闭环

先把两侧事实保存下来 ​

数据用途
渠道原始流水或账单文件保留渠道报告的原始事实与采集版本
本地支付、退款与订单记录反映本地处理结果
对账运行记录保存窗口、页游标、完成范围和重跑版本
差异记录保存匹配键、差异类型、核对进度

金额先统一币种和最小货币单位,分开处理收款、退款、手续费与结算。订单金额、支付金额和到账净额不一定相同,不能只比较两个总数就下结论。

表结构与操作入口 ​

记录关键字段与约束
reconciliation_runs范围、窗口、采集游标、源完整性标记、匹配版本、状态
channel_transactions渠道账户、交易 ID、类型、币种、金额、原始内容;来源身份唯一
reconciliation_items运行、匹配键、两侧证据、差异类别和差异版本
compensation_actions差异版本、动作种类、审批依据、稳定幂等键、执行结果

定时器和手动补跑接口都创建运行记录,查询接口返回采集进度与差异分布。复核、批准和重放接口分别校验权限并保存操作者与原因,不提供一个绕过差异核对的通用“强制成功”按钮。

本地支付、退款流水应有不可混淆的业务身份,不能仅用订单号判断一对一匹配:部分支付和多次退款可能让一个订单对应多条资金流水。

1000 条流水如何处理 ​

如果接口一页返回 100 条,1000 条约需拉取 10 页,这是分页示例,真实上限以渠道文档为准。以 Stripe 余额流水接口为例,它支持日期范围和游标分页;余额流水也不能直接等同于所有本地订单。

每页事务保存原始记录与检查点,按渠道流水 ID 建立唯一约束。只有确认所有页完整落地,才将采集阶段标记完成。失败后可以继续游标或安全重拉,不能把半份账单当成完整账单去判定“本地多单”。

持续变化的数据源可能让分页期间出现新流水。需要固定窗口和截止水位,或在后续批次回看重叠区间,通过唯一约束消除重复采集。

分页采集怎样保证检查点正确 ​

text
取得本轮采集资格,读取固定窗口和已提交游标
事务外调用渠道接口,取得一页与后续游标
BEGIN
  校验本轮仍属于当前采集尝试,游标仍等于请求起点
  幂等写入这一页原始流水
  保存这一页摘要和后续游标
  只有渠道明确没有后续页且完整性条件满足,才标记采集完成
COMMIT
匹配 Worker 只处理达到输入完整性要求的范围

调用渠道时不持有数据库长事务。返回结果后先落数据再推进游标,放在同一事务内;两者分开提交会产生跳页或不完整重复消费。

这里游标检查保护的是采集进度,来源交易唯一键保护的是数据身份。即使唯一约束消除了重复流水,过早推进游标仍可能跳过没保存的整页,两个机制不能互相替代。

如果源账单能够修订,记录来源版本或校验值并创建新的对账运行,不静默修改已经审核过的差异证据。

匹配和差异分类 ​

现象先核对什么可以安排的动作
渠道已收款、本地待支付回调是否丢失,交易是否属于该订单查询确认后幂等补记
本地已支付、渠道未出现渠道账单是否完整、是否仍有延迟记录待确认,稍后复核
金额或币种不符退款、部分支付、手续费和映射关系保留原始差异并诊断
同一订单有多笔收款是否分次支付或重复交易按既定规则审核处理
本地已关闭、渠道已收款关闭与支付的竞争结果建立差异处理单

单次查询没有返回,不等于资金操作失败。对账结果应区分“已确认差异”和“尚未取得完整事实”。

差异任务与补偿权限 ​

1000 条差异不应在扫描事务里直接执行退款、补款等动作。先保存可追踪的差异项,再根据预先确定的业务规则、审批流程和处理权限生成补偿任务。

补偿任务携带原交易、差异版本与稳定业务键。外部操作超时后先核对结果;无幂等保障的动作不能通过无限重试处理。

已经成功补记的差异不因整批重跑再次操作。差异状态可以从待确认、已确认、处理中推进到已解决,并保存解决它的业务流水。

补偿处理器怎样实现 ​

text
领取 compensation_action,核对规则版本与审批状态
重新读取差异、原支付和渠道当前结果
如果差异已经解决:关联已有结果,幂等完成
如果证据仍不完整:安排复查,不执行资金动作
如果满足允许的本地补记规则:
  同一事务写业务流水、解决差异、保存后续事件并确认任务
如果需要外部渠道动作:
  使用该动作稳定幂等键提交,保存请求身份
  超时进入待核对状态;查询原请求后再决定后续处理

审批与执行之间也会发生业务变化,因此批准不代表可以永远使用旧证据执行。补偿开始前要再次检查,批准记录本身不能作为操作已经完成的证明。

怎样报告结果 ​

对账完成时报告采集范围、原始条数、匹配条数、待确认差异和已确认差异。只通知“发现 1000 条差异”却不区分账单缺页、渠道延迟和真实问题,会制造不必要的人工工作。

告警按商户和差异类别聚合,具体条目进入受控的排查入口;通知中避免暴露完整账户信息。

第 7 页超时的一次完整恢复 ​

假设运行 C21 需要采集 10 页,每页样例 100 条,第 6 页已经提交:

故障或动作运行记录应怎样变化下一步
第 7 页接口超时游标仍指向第 7 页请求起点重试相同范围,不认定这些交易不存在
第 7 页落库,但提交响应丢失客户端不能确定结果重读检查点;必要时安全重拉
第 7 页重复返回唯一来源身份不产生重复流水数据与检查点一起确认
全部页完整保存本轮输入标记完整才判断两侧缺失与金额差异
发现渠道已付款、本地未记账创建带证据的差异项复核当前事实后走允许的补记流程

如果第 7 页尚未取得就开始判断本地多单,结果会把“未采到”错误解释成“渠道没有”。因此,对账运行阶段需要区分等待渠道、采集中、匹配中等状态;这些业务阶段与底层任务的 pending、running 等执行状态分别记录。

验收与排查依据 ​

场景应断言的结果
第 7 页保存前退出从已提交检查点恢复,前面页不丢失
写页成功但客户端未收到提交结果安全重拉,不重复创建原始流水
账单尚未完整生成运行等待,不把未出现的渠道记录立即认作差异
同一差异被两个补偿 Worker 领取本地业务约束或外部幂等键阻止重复动作
审批后用户已退款执行前复核,旧批准动作退出或重新审核
渠道请求超时但实际成功关联查询到的原结果,不更换请求键再次操作

监控源数据完整性、采集检查点年龄、未确认差异年龄和补偿待核对量。异常信息应能定位到交易证据,避免在告警中传播完整敏感流水。

美团配送对账体系中的二次核对 ​

美团技术团队在 2018 年的配送资金安全治理文章中,将对账拆成数据准备、核对和差错处理;按漏结、重复结、错结梳理问题,并结合明细核对与总数复核。文章还介绍了周期对账、在线核对,以及差错记录再次核实后进入自动修复或人工处理的设计。

这可以补充本文差异分类的开发方式:除逐条比较交易金额和状态,还按渠道、币种和账期保存笔数与金额摘要。明细用于定位具体记录,汇总用于发现漏采或规则覆盖不足;两边金额恰好相等也不能替代明细核对,因为相反方向的错误可能互相抵消。这是对该实践在本文模型中的应用推导。

差错处理器应保留首次证据、复核结果和处置身份。例如首次发现渠道已收款而本地未确认,复核时支付回调可能已经补齐,本次处理应标记差异已消除。仍有差异时才按授权建立补偿待办。该历史文章提供的是架构与阶段性实践,本文不沿用其当年的吞吐数字,也不将其描述为美团当前全部生产架构。

美团旅行结算:明细接收与账单计算分离 ​

美团的旅行结算平台实践讨论了另一个阶段的问题:单个账单写明细、计算汇总放在同一串行路径时,会限制处理效率。文章采用明细写入与账单计算分离、分散计算时机,并在最终结账时兜底计算。这是对结算平台的历史介绍,其选择依赖于业务接受中间状态最终收敛。

对照本文,账单页面上的暂时汇总、已经采集的交易明细、最终允许结算的金额应分别标记。若一批明细尚未齐备,界面可以展示“更新中”,但不能把临时汇总作为补付依据。跨系统核对还要保存对账口径、输入完整性与复核证据。

例如某商户新增一条退款,明细已经落库、汇总尚未重算,此时差异可能来自计算时差。复核器应等到约定水位或重算完成后再判断;确认是实际错账后才进入补偿。不能把原文特定环节的解耦优化推广成“对账和付款都不需要事务”。

参考资料 ​