第十六章 · 备战¶
九月七日,星期一,下午两点。
纪衡的邮件发在全员列表里,标题是"十一大促备战启动——技术方案与成本预估要求"。附件是一个 Excel 模板,五个 sheet:系统现状、容量评估、资源需求、成本预估、收益预估。正文最后一行单独成段:"上一版价值量化退了三次才过。这次还有谁写不出投入产出比?"
邮件没有点名。全员列表里三十七个人,价值量化被退三次的只有他一个。
结算系统过去六个月的数字他一个下午就查完了:日均三万笔,月末峰值六到七万笔,去年双十一四十万笔。当前 CPU 百分之二十三,内存百分之四十五,连接池使用率百分之六十七,上限一百。这五个数字他抄在记事本第一行。
监控面板他翻到了最底下两栏。数据库慢查询日志过去三十天累计四百一十二条,全部集中在每月最后两天,最慢一条一千八百七十毫秒,语句是对账明细的全表扫描。JVM 老年代回收平均每四十七分钟一次,单次停顿一百二十毫秒以内。这两栏他抄在记事本第二行,后面标了一个问号。
星期三,九月九日,上午十点。
第一版方案五个 sheet 全部填满,数字全部来自系统真实数据,没有一个是估的。他发给了易文。
四十分钟后,易文回:方案收到了。你过来一下。
三楼会议室,易文面前摊着一台笔记本,屏幕上是他方案的第一页。
"你这个方案,讲的是你需要多少资源,不是你能赚多少钱。"
"资源需求那一页我写了服务器型号和单价。"
"纪衡不看单价。他看这二十万花出去,回来多少。"
"回来多少我算不出来。事故是没发生的事,没发生的事没有数据。"
"有。你去年一年的资损单、事故工单、人工介入工时,三张表。"
陈稳算了三十分钟。过去一年资损七笔,合计十九万;事故十一起,处理时长共一百四十七小时;人工介入按人力成本折算约十四万。三个口径加起来,减去二十万年成本,净收益四十万。
七笔资损单里有一笔的处理人是梁栗,金额四万三,工单号 SETL-2024-0217,结论一栏写着'配置未同步,已手工冲正'。这笔他按原样计进了十九万,处理人那一列没有写进方案。写上去,纪衡会问梁栗现在在哪。
"四十万。"
"记住这个数。现在把方案改一版,标题改成'结算系统大促备战投入产出分析',第一页现状,第二页风险,第三页方案,第四页投入产出比。每页不超过五行字。"
"五行。"
"五行。多的字,写在附件里。"
陈稳改完发过去。易文看了五分钟。
"第一页现状数据太多。十四个数字,压到三个。"
"哪三个。"
"日均三万,峰值六万,成功率四个九。剩下十一个放附件。"
"第二页风险呢。"
"写具体的:双十一峰值预计四十万笔,当前架构未经过四十万笔压测验证。别写'存在容量风险'。"
"第四页那些'约'字。"
"全删,精确到万元。你写'约六十万',纪衡会问你到底是五十九还是六十一。"
三个口径他重算了一遍:资损十九万,事故一百四十七小时折人力二十七万,人工介入十四万,合计六十万。第一遍算出来是五十九万八。
"差的两千在哪。"
"事故工时取的整。"
"附件里写原始值。正文写六十万。"
陈稳全部改完,发给易文。
"可以了,发给纪衡。"
鼠标停在发送键上,没有按下去。他把方案往回翻了一页,又翻回来。
"你帮我改了三版。你花了多少时间。"
"四十分钟。"
"你本来可以不用帮我的。"
"对。"易文合上笔记本,"但是你现在学会了,以后我就不用帮你了。"
陈稳把方案发给纪衡,正文一行:结算系统大促备战方案,投入产出比四比一,详见附件。
九月九日,下午三点,纪衡的回复:方案收到。周四下午两点,三楼会议室,拉数据组一起评审。
星期四,九月十日,下午两点。
三楼会议室五个人。纪衡在长桌一端,面前一台笔记本。蒋辉在纪衡右手边。易文在长桌对面。另外两个是数据组和运维组的。
陈稳讲了六分钟,四页,每页五行。现状:结算成功率百分之九十九点九九,日均三万笔,峰值六万笔。风险:双十一峰值预计四十万笔,当前架构未经过压测验证。方案:扩容两台服务器,优化连接池,压测验证。投入产出比:年成本二十万,减少资损和事故成本六十万,净收益四十万。
没有卡顿,也没有人打断。
"你那个净收益四十万,怎么算的。"纪衡说。
"过去两年,日均三万笔的时候资源不足导致事故的概率是百分之零点三,日均六万笔是百分之一点二。四十万笔是日均的十三倍。"
"十三倍不能线性外推。"
"没有线性外推。按对数拟合,概率区间百分之十五到十七。取下限,预期损失六十万。"
"你那个对数拟合,能给我看一下吗。"蒋辉说。
计算过程投到屏幕上:一个公式,一个数据点表格,一个拟合曲线图。八个数据点,两个离群点标成灰色,注明了剔除原因。
蒋辉把两个灰点看了一会儿。剔除原因写的是"机房断电,与容量无关"。他没有再问。
那两个点是去年七月二十一号和二十二号。机房 B 区双路市电中断,柴油发电机切换失败,结算和风控一起挂了四个多小时。那次的故障复盘文档还在归档目录里,作者一栏写的是蒋辉。这件事陈稳知道。剔除原因他只写了一行字,没有写日期,也没有写复盘文档的编号。
"你什么时候学的对数拟合。"易文说。
"星期一。我不会,查了一下。"
会议室安静了三秒。
"方案可以。"纪衡说,"按这个执行。扩容两台服务器,本周内完成。压测排在下周三。数据组配合出压测数据。运维组配合出资源。周五前,把详细的执行计划发给我。"
"好。"
纪衡先走。蒋辉在门口停了半秒,冲他笑了一下,也走了。
易文没有走。
"你那个方案,我帮你改了三版。你知道我改的最多的是什么吗。"
"什么。"
"不是数字,是顺序。你的第一版,把现状放在第一页,把方案放在第三页,把投入产出放在最后。纪衡想看的是投入产出,不是现状。你让他先看到结果,他才会看你的过程。"
第一版的页序是他照着老梁三年前那份《结算系统容量评估》排的。老梁那份也是现状在前,投入产出在最后一页。那份文档在归档目录里,最后修改时间二零二三年三月,没有人回复过。这件事他没有说。
"你记住了吗。"
"记住了。"
易文走了。记事本上他写了一行:先给结果,再给过程。纪衡想看的是投入产出,不是现状。
星期五,九月十一日,上午九点。
执行计划发给纪衡:扩容两台服务器,预计周三完成。压测排在下周三下午两点。数据组和运维组已确认资源。
纪衡没有回复。
字段对齐方案他又核了一个小时,三十九个字段,类型和空值率都对得上。结算成功率百分之九十九点九九,拦截器正常,连接池使用率百分之六十五,上限还是一百。
慢查询日志比上周多了九条,全是对账明细那条全表扫描,最慢一千九百四十毫秒。九条的时间戳排成一列,八条落在九点到九点半之间,那是对账任务的固定窗口。他想在执行计划里加一条"对账查询加索引",最后没有加。加索引要过数据组的变更评审,最近的评审窗口排在十月八号,赶不上大促。
下班前,易文的消息:方案通过了。下一步,在压测之前先做一个预演。你一个人,跑一遍完整的流程,确保每一步都走通。
他回了一个字:好。
星期六,九月十二日,上午十点二十三分。
阳光从窗帘缝隙里透进来,照在地板上,一条光带。压测预演脚本跑了一遍,所有步骤走通。记事本上写着下周三件事:星期一确认服务器到位,星期二配置环境,星期三压测。
下午两点,小区门口。何晚穿了一件白色的短袖。
"走吧。"
"去哪里。"
"不知道。先走走。"
路口红灯,等了一会儿,绿灯。
"最近怎么样。"
"还行。"
"公司又要搞大促了吧。"
"嗯。双十一。"
"又要加班。"
"嗯。"
公园里一张长椅。阳光照在草地上,有个小孩在跑,跑得很快,后面跟着一个大人,跑得很慢。
"你那个胃,怎么样了。"
"好了。"
何晚看着那个小孩跑了一圈,又跑了一圈。
"你上次说,还行。你每次都说还行。"
"这次是真的还行。方案过了,六分钟,没被打断。"
"过了之后呢。"
"下周三压测。四十万笔。"
"我问的不是这个。"
"我知道。"
"那你回答我。"
"我不知道怎么说。"
何晚看着前面。大人跟在小孩后面,跑得很慢。
"你变了。"何晚说,"你变了,但你不知道你变了。你以前不会说'我不知道怎么说'。你以前只会说'没事'。"
"哪句更好。"
"都不好。但后面那句是真话。"
下午四点,小区门口。
"你下周,压测完了,给我发个消息。"
"好。"
"别忘了。"
"不会忘。"
何晚笑了一下,转身走了。
客厅。对面那栋楼一格一格亮着,他看了十一个月的那扇窗还是黑的。
压测脚本的注释他补完了:大促压测脚本。模拟四十万笔结算请求。分十批,每批四万笔。每批间隔五分钟。监控指标:结算成功率、响应时间、连接池使用率、CPU、内存。
星期一,九月十四日,上午九点。
运维组的邮件:服务器已到位,系统已安装,网络已配置,IP 地址如下。两个地址,10.14.2.31 和 10.14.2.32。他把两个 IP 抄进记事本,抄完停了一下,往前翻到八月十一号那一页,那一页上写的是 10.14.1.88。不同网段。他把本子翻了回来。
他回了一个字:收到。
一个上午配完两台服务器:依赖、防火墙、负载均衡、连接池配置。新机器 CPU 百分之二,内存百分之十二,连接池使用率百分之三。记事本上"星期一确认服务器到位"后面打了一个勾。
配置项是一条一条对过的:JDK 版本 1.8.0_312,和老机器同一个小版本;防火墙放通 3306、6379、8080 三个端口;负载均衡权重先给 10,老机器还是 100;连接池参数照抄老机器,min_idle 十,max_wait 三千毫秒,validation_query 是 select 1。两台机器从上电到接流量,一共三小时四十分钟。
星期二,九月十五日,上午十点。
环境配置完,预演跑通,从数据准备到压测执行到结果收集,一步不落。他给纪衡发消息:环境已配置,预演已通过,压测时间定在明天下午两点。
纪衡没有回复。
星期三,九月十六日,下午两点。
三楼会议室三个人:易文,数据组的人,运维组的人。纪衡不在。
"纪总呢。"
"他说晚点到。"
第一批四万笔,五分钟后数据回来:结算成功率百分之百,平均响应时间四十七毫秒,连接池使用率百分之二十一,CPU 百分之十二,内存百分之十八。
"正常。"运维组的人说。
第二批到第五批全部正常。
第六批到第八批,平均响应时间从五十一毫秒升到六十三毫秒,连接池使用率从百分之二十四升到百分之三十八。
"还在正常范围。"
"连接池是线性涨的。"陈稳说。
"最高四十二个百分点,怕什么。"
"四十万笔是十批分开跑的。真到双十一,是一起来的。"
第九批,第十批,数据全部正常。四十万笔,全部成功,结算成功率百分之百,平均响应时间最高六十九毫秒,连接池使用率最高百分之四十二,CPU 最高百分之二十三,内存最高百分之三十一。
第十批跑到第三分钟,他在库端敲了一条 show status like 'Threads_connected',读数三百九十四。max_connections 是五百。
"库端多少。"运维组的人说。
"三百九十四。"
"还有一百多,够。"
这一百多里有多少是别的服务占着的,运维组的人没有算。
"没有问题了。"
易文在收笔记本,手停了一下。
"分十批,中间隔五分钟。连接池每次都归零重来。"
"我知道。"
"那你报告里写清楚。"
报告标题:"结算系统大促压测报告——四十万笔并发,成功率百分之百"。第二页第三行他加了一句:本次压测为分批施压,未验证瞬时并发峰值。他发给了纪衡。
纪衡没有回复。
停车场。记事本上"星期三压测"后面打了一个勾,后面写:压测通过。四十万笔。成功率百分之百。分批,非瞬时。
地铁上,易文的消息:压测数据我看了,没有问题。你那个报告,加一句话:下一个瓶颈是数据库连接池,建议在双十一前将连接池上限从一百调到两百。
他回了一个字:好。
隧道里的灯一格一格往后退。易文说的每一句话都对应一个数字。她说的不是结论,是可执行的下一步。这一行他写进记事本,写在"先给结果,再给过程"下面。
到家。给何晚的消息:压测完了。通过了。
何晚没有回复。
水是凉的,胃没有反应。
结算成功率百分之九十九点九九,新服务器运行正常,连接池使用率百分之六十一。
他打开 IDE,改了一行配置。max_pool_size 从 100 改成 150。
改成 200 的话,两台新服务器每台要多分四十个数据库连接。库端 max_connections 是五百,结算、对账、营销三个服务加起来已经占了三百八十。他算了两遍:两百会把库端逼到四百四十,一百五是四百一十。
三百八十这个数是压测那天从库端拉的实时值,不是配置上限。营销组下个月要上一个新的活动接口,运维组那封资源邮件里申请了六十个连接,收件人是运维组和纪衡,抄送里没有易文。六十个加上去,两百的方案会把库端压到五百整。这件事陈稳知道。
提交,推上去。commit message 写的是:chore: 连接池上限 100 -> 150(大促备战;库端 max_connections 余量不足,未按建议调至 200)
括号里那半句他删过一次,又写了回去。
这件事他没有告诉易文。
他起过一个念头,把库端余量那三行计算截图发给易文,让她判断一百五够不够。消息框里打了两行字,又删掉了。易文要的是可执行的下一步,他现在拿不出四十万笔瞬时并发下连接池会涨到多少的数据——压测是分十批跑的,中间隔五分钟。
记事本最后一行:双十一。四十万笔。压测通过。下一步:数据库连接池优化。一百五。
对面那栋楼的窗户,一格一格地亮着,他看了十一个月的那扇窗,还是黑的。
← 第十五章 翻译 · 目录 · 第十七章 凌晨三点 →