第五十章 · 重写¶
周二上午十点,周会。蒋辉的排班规则二十分钟过完,没人反对。轮到对账排期,陈稳把笔记本转了个方向,屏幕上两栏:剩多少,卡在哪。
蒋辉先开口。
「你周一下午三点十九,建了个分支。feat/reconcile-realtime。」他说。「排期表上没有这一条。」
会议室静了两秒。王磊在笔记本上写了半个字,停住了。
分支是三点十九建的,这个时间陈稳记得。他不知道蒋辉在看那个仓库的提交流。这是他周一晚上就该想到的问题。
「做什么的。」纪衡问。
「T+0。对账从 T+1 逐笔比对,改成事件驱动加增量比对。」陈稳说。「排期表上没写,因为周一晚上之前,它还只是一个分支名。」
「现在呢。」
「现在它有四个模块的拆解了。」
蒋辉端起杯子喝了一口,没插话。
「排期我讲完。」陈稳说。「六条业务线,四条平稳。剩两件事:汇金线台账精度,周三我去对;四千四百一十二笔差异单拆完了,按月按线四十行,表在纪总那儿。卡的只有一块——T+0 没法在现在的表上做。」
「哪张表。」纪衡问。
「settle_reconciliation。没有分区键。」陈稳说。「去年顾源说过,T+0 之后写入量是现在的四倍,半年后分区成本是三倍。这张表去年七月二十八号建的,索引八月一号被人删过两个。」
八月一号这三个字落在桌上。没有人去掀。
「重构和重写,差多少。」纪衡问。
「重构是把旧路修平。这张表修不动——分区键加不上去,硬加要停写八小时。」陈稳说。「重写是换路。新表按月 RANGE 分区,八个月历史数据迁过去,新旧链路影子跑两周再切。」
「影子跑两周,写入翻倍,窗口谁批。」
「夜窗口。回放走凌晨一点到五点,跟报表任务错开。」陈稳说。「汇率回补那次踩过的坑,我不会再踩。」
「旧链路上那四千四百笔自动核销的差异单,重写之后怎么办。」
「历史欠账。差异单先封存进备份库,核销规则一起改——千分之三以内也通知业务线,状态从 auto_accepted 改成 auto_accepted_notified。」陈稳说。「旧数据不动。」
纪衡的手指在桌面上停了一下。
「封存。」他说。「动库之前来找我。」
纪衡在纸上写了两个数,写完把纸扣过去。
「人力。」
「我一个,三个月。」
「新人组里还有两个没独立值班。」纪衡说。「这个项目要值班的。排班我给王磊说。」
「你去年写的 OKR 是重构,三月前交。」纪衡把笔帽扣上。
「时间没变。路径变了。」
纪衡抬起头,目光在陈稳脸上停了两秒,落回纸上。
「立项页,最后一个工作日下班前给我。一页。」他说。「架构评审自己约人。组里约不动的,顾问库里去约。离职的人,联系方式都在。」
散会的时候蒋辉留到最后,等王磊他们出去。
「人手的事,想好没有。」
「查到要动库的时候说。」
「那就快了。」蒋辉说。「动库这种事,从来不会提前打招呼。」
下午三点,他做了一件排期表上也不会有的事。
settle_diff_order,状态等于 auto_accepted 的四千四百一十二笔。备份表没有建在业务库里,建在 settle_archive——业务库的清理脚本碰不到它。
CREATE TABLE settle_diff_order_aa_20260801_bak AS SELECT * FROM settle_diff_order WHERE status = 'auto_accepted';
跑完先对行数:4,412。再对金额:SUM(diff_amount) = 96,340.00。两个数,和上周报给纪衡的一分不差。
备份表上挂了 DDL 告警。任何人在这张表上执行 DROP 或者 ALTER,他的手机会响。
commit message 写了三行:
chore: auto_accepted 差异单迁移前快照
八月一日变更留底。重写先迁证据,再迁数据
校验:行数 4,412 / 金额 96,340.00,与 2027-01-29 汇报一致
推完他在注释区补了一行:-- 本表只增不改。
傍晚王磊端着笔记本过来,身后跟着那个下个月要独立值班的新人。
「白天会上没好意思问。」王磊说。「新人读周报模板,读到『问题比事实有用』那一栏,问了我一个问题——为什么差异单可以不通知业务线。我答不上来。」
「答案不在模板里。」陈稳说。「在八月一号。」
「那我周报怎么写。」
「就写:这是个问题,还没查完。」陈稳说。「那句话的意思是,答不上来,就照抄问题。」
新人把这两行记进手机备忘录,道了谢回去了。王磊在原地站了一下。
「你回来以后,组里安静了很多。」他说。「以前不是这样的。」
「以前哪样。」
「以前出事才有人说话。」王磊说。「现在没事也有人问问题。」
他走了以后,陈稳把周报模板最后一栏打开。问题比事实有用。底下他添了一行注:答不上来的时候,把问题原样放进周报。放进去了,下周就有人答。
夜里十一点,办公室只剩他一盏灯。他把影子跑的回放脚本又跑了一遍。
十二月第一周,二十一万一千三百笔。新链路输出差异单四百零二笔,旧链路四百零九笔。七笔不一致。他把七笔的日志拉出来,逐条对着看,每一笔的偏差都在同一处:回放时间戳取整到分钟,窗口边界上的两笔被划进了不同的窗口。
他把取整逻辑改成按秒,重跑。归零。
四点零七分,他在记事本上写:「七笔不一致,全是同一个原因。系统不说谎,说谎的是取整。」写完想起来,这句话的句式是顾源的。他把本子合上,灯关了。
周三上午九点半,汇金业务线,财务共享中心三楼。访客码是提前一天申请的,访客机吐出一张贴纸,他贴在袖口。对账岗叫马菁,在这个岗上坐了五年,工位右侧立着一摞台账复印页,边角全卷了。
陈稳带去一张表:十一月,汇金线差异单四百三十一笔,全部状态 auto_accepted,差额千分之三以内,自动核销,不生成异常单,通知数零。
马菁倒了杯热水放在他手边,然后从头到尾看完,把表打印了一份,又从头看了一遍。
「这些单子我们看不见。」她说。「系统里我们没有权限。我们手上一直只有两个数——台账,和回执。」
「台账的数从哪来。」
「每月五号以前,结算那边发一封核定数,我们照着填。」马菁说。「以前是孙宇发。孙宇的数,月底跟系统导出来能对上。后来是张毅发。张毅的数,对不上。」
「差多少。」
「低。永远低一点。」她说。「十一月那封写四万三千二,实际四万四千一百八。我们台账上是四万三千二。差的九百八十笔,我们找过,找不到。」
陈稳把表翻到第二页:四百三十一笔,最大单笔差额不到四块钱,全部在千分之三以内。他把这一页转过去。
「在这。」
马菁盯着那一页,手指从第一行划到最后一行,划完把打印纸扣在桌上。
「十个月。」她说。「我们照着一个对不上的数报了十个月。台账错了十个月,这个算谁的。」
「算系统的。」陈稳说。「你的台账是抄的。抄的人没错,错的是给你抄的东西。」
马菁把打印纸收进抽屉,上了锁。
「邮件还在吗。」陈稳问。
「在。系统不让删。」她说。「十一个月的核定数邮件,今天下午转给你。十月那封在旧邮箱,归档了,要提工单调,快的话下周。」
「这个事,会有人来问我们吗。」她问。
「不会。」陈稳说。「这是我的表。」
马菁把椅子往后挪了半寸。
「孙宇发数的时候,你们对得平。」陈稳说。「孙宇离职之后,第一个月开始对不平。中间隔了多久。」
「一个月。」马菁说。「十月就开始不对了。我们提过一次,回复说口径调整,让我们以核定数为准。」
「谁回的。」
「邮件。不署名,部门邮箱发的。」马菁说。「我们提完那一次,就没有再提。一个对账岗,提第二次,就轮到岗位被评估了。」
她把热水壶放回底座。
「你这张表,」她说,「以后每月给我们一份吗。」
「以后不用你们对核定数了。」陈稳说。「系统直接推,笔笔可查。这个月是我最后一次拿表来找你。」
「那挺好。」马菁说。「五年了,我第一次听见有人这么说。」
下午三点十七分,邮件到了。十一封,发件人一栏同一个名字:张毅。陈稳把每封的日期和数字抄进记事本,抄完写了一行:
「数从张毅手里出来,差额在配置里消失。两个管道,一个方向。核定数永远比实际低——低的这十一封,现在在我邮箱里。」
周四早上九点,赵岩的回复到了。
「MAC 00:1A:2B:3C:4D:5E,资产编号 TPL-TC-0342。2025 年 6 月入账,归属技术支持中心,登记使用人:孙宇。」赵岩写道。「资产状态:在用。上次盘点 2026 年 11 月,盘点签字:张毅。」
陈稳把这段读了三遍。
孙宇离职十三个月。机器没有回收,挂在技术支持中心名下,DHCP 池认它。八月一号它删了索引,一月二十二号它登进配置中心,把结算命名空间从头到尾查了一遍,没有改任何东西。资产账上写着:在用。
他回:「盘点写『在用』,谁核的。」
「盘点各部门自己盘,资产系统只收结果。」赵岩说。「签字就是责任人。要问我的意见——这台机器现在插在谁的桌上,技术支持中心一口就能答上来。」
十点四十,他更新工单,抄送纪衡,正文一行:「八月一日与一月二十二日操作机器,定位为孙宇名下未回收资产,现登记在用,盘点人张毅。下一步:确认设备物理位置与当前使用人。」
十一点整,纪衡回了两个字:「查。」
下午两点,立项页写完。一页 A4,四段。
一、问题。settle_reconciliation 无分区键;八月一日两个索引被删;同日开启差异单静默核销,至今四千四百一十二笔、九万六千三百四十元,业务线无一方知情。对账跑在一张不可信的表上。
二、方法。事件驱动:settle_message 消息进入,增量比对按商户加币种对开滑动窗口,窗口十五分钟——和他去年六月给规则引擎写的重试间隔是同一个数,这个数验证过三个月。新表 settle_reconciliation_v2 按月 RANGE 分区。差异单通知规则改造:千分之三以内也通知业务线,状态记 auto_accepted_notified。
三、验证。新旧链路影子跑两周。回放十二月第一周,二十一万一千三百笔。这一步他昨天夜里跑过一遍:新链路输出差异单四百零二笔,旧链路四百零九笔,七笔不一致,逐条核过去,全是回放时间戳取整的问题。修完重跑,归零。
四、评审。架构评审人:____。
第四段那一栏,他空着。
commit message:
feat: 对账链路重写立项页——事件驱动+增量比对+月分区
影子跑回放 211,300 笔,新旧差异 7 笔,归因回放时间戳取整,修复后归零
四点,纪衡办公室,门开着。他把纸放在桌上。
「为什么是现在。」纪衡问。这个问题不在立项页上。
「八月一号,索引被删两个,静默核销打开。同一天。」陈稳说。「我上个月才知道是同一天。表不可信,T+0 做得再快,也是在错的底座上跑——快也是零。」
「汇金那边呢。」
「核定数是邮件,不是系统。每月五号,张毅发的,永远比实际低。」
「为什么往低报。」
「不知道。可能是习惯,可能是别的。」
「别猜。」纪衡说。「十月的数拿到再猜。这个发现写进立项页问题段了吗。」
「写了。」
纪衡把纸翻到第四段,手指停在那个空栏上。
「评审人为什么不填。」
「顾问库里有一个名字。」陈稳说。「我先问他愿不愿意。」
纪衡没有问是哪个名字。他把纸推回来。
「春节回来给我答案。复工第一天,评审要有日期。」
四点五十,六页清单重新导出。第七页,静默兜底全量清单,结算系统那一行的来源栏空了两个星期。他填上:
2026-08-01 23:09:41 / settle.reconcile.auto_accept.enabled / 账号 root / 来源 10.14.1.88
附注:该 IP 于 2027-01-22 21:14:03 再次登录配置中心,仅查询,变更数零。
发送给万钧,正文一行:「清单补来源。查完了。」
五点十分,放假前最后一个工作日结束。万钧没有回。
办公室走廊里已经有人在贴福字。老位置那台打印机吐出一页纸,没人取。他把抽屉锁好,钥匙收进包的外袋——外袋里还有那页折过角的记事本。
晚上七点四十,他爸来电话。
「厂里放假不。」
「今儿最后一天。明早六点四十的车。」
「到站去接你。」他爸说。「你妈腌了鱼。初二你姑来,你别走那么急。」
「嗯。」
电话那头他妈喊了一句,问他路上吃什么。他说车上买。
「厂里今年稳不稳。」他爸问。
「稳。」他说。
挂了电话,他把抽屉里两盒并排的胃药拿出来,旧盒倒出两粒,吃了。新盒的封没拆。
新盒是他上周五自己买的,同一牌子,药店最后一盒。他想起去年她把药放进他抽屉的时候说过的那句话。那句话他记不全了,记得清楚的是药不能断。
周五,除夕。车站安检的队伍不长。背包里是记事本、顾源的打印件、那页折了角的纸。
车开出去二十分钟,手机震了一下。万钧的回复:
「收到。查到人了吗。」
他回了一个字:「还没。」
万钧没有再回。这不是他要的答案,但两边的账都清了:清单补了,来源给了,剩下的路在这条线上,不在他手里。
然后关掉对话框,点开顾问库的通讯录。那个名字在第三屏。号码是去年十月底从架构组内部系统抄的,那天他去五楼,那个工位上只剩一圈白色印子。三个月,一个字没改过。
他打了一行字:
「顾工,新年好。有个立项想请您做架构评审——对账链路重写,一页纸。您什么时候方便,电话联系。」
发送。
消息发出去,他把手机扣在小桌板上。车速稳下来以后,他把那页折了角的记事本从外袋抽出来,摊平。折角是上周日折的,折痕比原来深了一道。他顺着折痕把纸对折,再展开,摊在腿上。
对面座位的孩子举着一盏小红灯笼,电池快没了,一明一暗。车过淮河,河面上结着薄冰,冰在太阳底下亮了一下,又暗下去。桥墩下面泊着几条捕鱼的船,一动不动。
← 第四十九章 回来 · 目录 · 第五十一章 顾问 →