晚上九点四十四分,临时账号正式启用。
周衡没有先碰重启按钮。
他让罗致远把订单确认延迟、数据库写等待、消息积压和计划任务放到同一个只读页面。四条曲线的时间范围全部拉回晚上六点半,避开扩容和多次重启造成的后续噪声。
最先变化的不是订单量。
七点零一分,一项“未确认订单对账”任务开始运行。数据库写等待几乎同时抬头,五分钟后订单确认开始变慢。海拓第一次增加消费进程时,等待连接数进一步上升;第二次扩容后,积压增长更快。
海拓值班负责人仍认为消息队列本身是瓶颈,提出先把队列节点再扩一组。
周衡让他把队列写入速度和消费确认速度分别拉出来。消息一直能正常进入,磁盘和网络也没有接近上限;真正下降的是订单写入完成后的确认。队列只是把来不及处理的订单保存下来,不是最先变慢的地方。
“扩队列能放下更多积压,不能让数据库更快写完。”他说,“先不动它。”
“这个对账任务今晚为什么提前跑?”周衡问。
丁卓在现场终端旁查工单:“下午改过执行时间。业务想在大促前先清一次历史未确认订单,变更单批准时间是六点四十分。”
“谁执行的不是重点。先看它做了什么。”
任务日志显示,它每次读取一批未确认订单,更新状态前还会调用仓储接口核对出库结果。外部接口一慢,数据库事务便一直不结束,同一批订单记录也始终被占着。
正常的订单确认进程需要更新其中一部分相同记录,等不到便超时重试。海拓增加的进程越多,同时排队等待的连接越多,最后连不相关的新订单也拿不到写入机会。
周衡没有凭这一条时间关系直接下结论。
他让数据库管理员保存当前活动事务、等待关系和任务日志快照。最长的一笔事务正来自对账账号,持续二十六分钟;后面排着四百多次订单确认写入。录屏完整拍下查询条件、结果时间和操作人。
“先停任务调度,不杀事务。”周衡说,“停止下一批进入。当前这批要确认已经做了哪些外部调用,直接终止可能让仓库状态和订单状态分开。”
罗致远在工单里批准暂停调度。
丁卓执行,回读状态:“调度已停,当前事务还在。”
仓储接口日志由嘉禾人员核对。当前批次发出过三百余次查询,没有写出库指令;数据库更新也尚未提交,终止后只需回滚本地未完成状态,不会撤回已经生效的业务动作。
这一结论被写进工单,数据库管理员才终止对账事务。
回滚用了七分钟。
写等待开始下降,积压曲线却没有立刻回头。前面扩出的消费进程仍在同时重试,数据库连接刚释放,便被大量旧请求再次占满。
“把并发降回原来的四分之一。”周衡说,“先别追求清积压,确认新写入能稳定完成。”
杜维成不在现场,海拓值班负责人在语音里质疑:“现在积压这么多,再降并发什么时候能清完?”
“现在的瓶颈是写入等待,不是进程数量。先让每一笔能完成,吞吐才会回来。继续加,只会让更多请求一起等。”
罗致远问:“回滚条件?”
“降并发后五分钟内,单笔确认耗时和等待队列没有持续下降,就恢复原配置,改走只读降级。现在所有变更值都写进工单。”
客户批准。
丁卓按记录把进程数降下来。第一分钟,积压仍然增长;第三分钟,数据库等待从高位落下一半;第五分钟,订单确认成功率开始恢复。
新的问题随即出现。
历史积压还排在前面,新付款订单即使能写,也要等旧订单逐条处理。继续按原顺序清,核心链路的延迟不会很快恢复。
嘉禾的消息系统支持独立消费组。周衡提出开一组临时进程,只从当前时间点以后接收新订单;原消费组保留旧位置,等数据库稳定后再处理历史积压。同一订单可能因重投进入两边,因此必须先验证订单号的唯一约束和重复确认逻辑。
现场测试确认,相同订单号重复投递不会重复确认。罗致远随即批准临时通道。
十点二十六分,第一笔新订单从临时通道完成确认,用时二十八秒。
随后十笔、五十笔。
确认时间稳定在业务阈值以内,付款后的订单能够重新进入仓库。客服后台里不断增长的“处理中”数量第一次停住。
十点三十分,罗致远在应急时间线上标记:核心订单确认恢复。
从临时账号启用,到核心恢复,四十六分钟。
嘉禾没有只看一条成功率曲线就宣布结束。
业务人员现场下了三组受控测试订单:正常支付一笔,支付后取消一笔,同一请求重复提交一笔。第一笔在三十秒内进入拣货,第二笔按取消流程释放库存,第三笔只生成一个有效订单号。
仓库扫描员在另一端回读了结果,客服后台也能看到一致状态。确认链路恢复以后,罗致远才允许历史积压开始提速。
会议室里有人松了一口气,周衡没有让现场立刻把所有进程开满。
新订单只是恢复了,旧积压还在。
他让原消费组从低并发开始处理历史记录,每十分钟检查一次数据库等待、失败数量和重复确认。失败订单不自动跳过,先进入单独清单;确定只是短时超时的,按原订单号重放,字段不完整或状态矛盾的留给人工核对。
十一点,积压下降到峰值的六成。
十一点二十,仓储接口又慢了一次。周衡没有增加重试,只暂时降低历史处理速度,保证新订单通道不受影响。接口恢复后再逐级放开。
几笔地址字段不全的旧订单被单独交给客服核对,没再拖住后面的任务。丁卓看着队列一截截变短,肩膀终于放松下来。
“这个速度,再有十几分钟就清完了。”
海拓值班负责人一直没再提加机器。他盯着恢复的曲线,隔了好一会儿,才问周衡是不是可以把刚才的判断顺序写进处置手册。
“我会放进交付记录。”周衡说。
对方点头,低下去继续记。
十一点五十八分,积压只剩最后一小段。
午夜零点零一分,历史队列回到零。失败清单里的记录全部有去向,没有一笔被静默删除。
从九点四十四分开始,正好两小时十七分。
数据库管理员核完总数,向罗致远报了确认。会议室里响起几声压不住的欢呼,连一直守在门口的客服负责人都笑了。
两小时十七分,他们终于能把“系统恢复”发给前线了。
罗致远让仓库和客服分别抽查订单。新订单确认正常,旧订单没有重复出库,页面状态与仓库记录一致。
周衡保存最终指标,开始写遗留风险:对账任务必须拆掉外部调用与长事务;大促期间不得临时提前批处理;扩并发前先确认真正瓶颈;临时消费组在积压核对完成后下线。
他还没写完,会议室的门被推开。
杜维成从海拓赶到嘉禾,身后跟着一名项目经理。
他先看了一眼已经归零的积压曲线,又看向坐在屏幕旁的周衡。
“恢复了就好。”杜维成把电脑放到桌上,“接下来由海拓统一对客户汇报,外部人员先退出系统。”