知识

订单中心系统

时间:2010-12-5 17:23:32  作者:知识   来源:时尚  查看:  评论:0
内容摘要:订单中心系统最怕的不是流量高峰,是那种“看起来没问题”的订单。上周同事排查一个客诉,用户说付了两次钱,系统只显示一单。查日志发现,第一次支付回调被网关重试机制吞了,第二次回调进来时,订单状态已经是“已

订单中心系统最怕的订单不是流量高峰,是中心那种“看起来没问题”的订单。上周同事排查一个客诉,系统用户说付了两次钱,订单系统只显示一单。中心查日志发现,系统第一次支付回调被网关重试机制吞了,订单第二次回调进来时,中心订单状态已经是系统“已支付”,代码直接幂等返回。订单用户的中心钱扣了,订单没多出来,系统账上却多了一笔待处理金额。订单这种问题不炸则已,中心一炸就是系统财务对账时才发现,中间隔了三四天。

订单中心的核心就一件事:把“用户想买”到“钱货两清”之间的所有状态,用一条不可逆的流水线串起来。但这条流水线不是直线。它更像一棵状态树,每个节点都可能分叉。创建订单时,库存锁定成功但优惠券核销失败,订单是挂起还是回滚?支付成功但风控判定异常,是拦截还是放行?这些分叉点才是订单中心真正的工作量所在。

我见过一个早期系统,订单表就一张,状态字段用数字表示,1到9分别对应不同阶段。开发图省事,每次状态变更直接update。后来做数据报表,想统计“支付后取消”的订单占比,发现根本查不出来——因为状态从“已支付”跳到“已取消”,中间没有记录谁取消的、什么时间取消的、取消前有没有发起退款。整张表只有最终态,没有过程。补日志补了两个月,最后把订单表拆成主表和流水表,每次变更插一条记录,才把这事说清楚。

流水表的设计有个细节:时间戳必须用数据库的now(),不能用应用服务器的时间。两台机器时钟差几秒,排查问题时能把人逼疯。还有操作人字段,哪怕是系统自动触发的变更,也要写清楚是哪个服务、哪个定时任务干的。别写“system”,写“payment_callback_retry_03”。出问题时能直接定位到代码路径。

订单中心跟库存系统的交互最磨人。下单锁库存,支付扣库存,取消回滚库存。听起来简单,但锁库存超时了怎么办?支付回调比锁库存超时晚到三秒,库存已经释放了,这时候是重新锁还是直接失败?我们现在的做法是:支付回调进来先查订单状态,如果是“已取消”但支付成功,自动触发退款,同时给用户发一张补偿券。这个逻辑写在回调服务里,不走订单状态机,因为状态机已经认为这单结束了。补偿逻辑单独一条线,异步跑,不阻塞主流程。

对账是订单中心的照妖镜。每天凌晨跑批,把支付网关的流水跟订单流水逐笔比对。金额、时间、订单号,三个字段全对上才算平。对不上的分两类:一类是支付成功但订单没更新,这类通常是回调丢失,得手动补;另一类是订单显示成功但网关没记录,这类最危险,可能是伪造回调。我们遇到过一回,攻击者伪造了支付成功的回调,金额改成0.01元,订单中心没校验签名直接放行。后来加了签名验证和金额比对,但那次损失已经产生了。对账脚本跑出来才发现,中间隔了六个小时。

订单中心不是个“系统”,它是个账本。每一笔变更都得有据可查,每一个状态都得能回溯。别指望用一张表搞定所有事,也别觉得状态机是万能药。状态机管流转,流水表管记录,对账管兜底。三样缺一个,早晚出问题。出问题不可怕,可怕的是出了问题查不到原因。查不到原因的系统,修一次还得再炸一次。

最近更新
热门排行
copyright © 2026 powered by 力不从心网   sitemap