流量突增还是代码回归,先沿着时间线、单位成本、实例分布往下拆
接口突然变慢时,最容易浪费时间的不是排查,而是太早把问题说成“流量”或“代码”二选一。先把发布时间、流量爬升点、单位请求成本和新老实例分布放到同一条线上,通常更容易拆出触发器和承压能力变化。
线上接口一慢,现场如果同时满足两件事,最容易卡在错误的地方:
- 流量确实在涨
- 最近也确实刚发布过
很多团队一到这里就会很快站队:
- 一边说是流量冲上来了,先扩容、限流、削峰
- 一边说是代码回归了,不回滚只会越拖越坏
但真正值钱的,不是先选边,而是先把事故压回一条硬判断线上:
这次把系统推过线的,是外部触发器突然变强,还是系统自己的单位请求成本已经变贵、承压余量被提前吃掉了。
这两件事经常同时存在,但主次不同,处理顺序就会完全不同。
所以比起先争“锅在哪”,更有用的是先沿着三条证据往下拆:
- 时间线
- 单位请求成本
- 版本 / 实例分布
第一件事:先把时间线排出来,看谁先动
先不要急着看一堆总量图,先把几个关键时间点摆平:
- 最近一次发布是什么时候
- 流量是什么时候开始明显抬升的
- RT、错误率、线程池排队、数据库等待分别是什么时候开始变坏的
这一步的价值很直接:很多争论一对时间线,主次就已经缩小了一半。
常见的几种线索
情况一:发布后很快变差,高峰只是把问题彻底放大。
这通常说明系统承压能力已经先降了,只是低流量时还没完全露出来。等到流量再往上推一截,就直接穿线。
情况二:发布后一直平稳,直到流量冲到某个阈值才突然失稳。
这更像流量是主触发器。系统可能本来就接近边界,但真正把它推倒的是总量或并发跨过了阈值。
情况三:发布后有轻微变差,但现场真正爆炸和流量爬升高度重合。
这类最常见,也最容易吵。因为它往往不是单因子事故,而是“承压能力先掉一点,再被流量补上最后一脚”。
所以看时间线,不是为了把问题粗暴压成二选一,而是先回答:
- 是不是发布后就已经埋下了性能变化
- 流量是在什么时候把这个变化放大成事故的
第二件事:看单位请求成本,有没有“同样请求变贵了”
总量上涨本身当然会让系统变难受,但真正区分“只是人变多了”还是“每个人也更贵了”的,通常不是总 QPS,而是单位请求成本。
这里更值得盯的是:在相近流量区间里,新旧时段相比,每个请求到底贵了没有。
可以重点看几类东西:
- 单请求 RT
- 单请求 SQL 数量和 SQL 耗时
- 单请求 RPC / 下游调用耗时
- 单请求 CPU、内存、对象分配或线程占用时间
如果这些指标在相近流量下明显变坏,基本就不能把问题简单归成“今天流量大”。
因为这说明系统接住同一份流量时,自己先变笨重了。
为什么单位成本比总量更能拆主次
看总量时,现场很容易得出一句正确但没用的话:
“请求确实比平时多。”
这句话通常不假,但它只是在描述触发器,不是在解释为什么系统这么快就扛不住。
更有用的问题是:
- 以前一万请求能扛住,现在为什么八千就开始抖
- 以前这个接口高峰 RT 只是涨一点,现在为什么直接把线程池拖满
- 以前数据库有余量,现在为什么同样业务量就开始慢查询增多
这些答案往往不在“来了多少请求”,而在“每个请求把资源吃成什么样”。
如果单位成本明显上升,那么流量可能只是导火索,真正缩小容量边界的是代码、配置、依赖路径或缓存命中变化。
第三件事:看版本和实例分布,问题是偏新实例还是全局一起坏
时间线和单位成本能帮你看清有没有回归,但现场还需要再补一刀:
这次变坏,是不是明显偏在新版本实例上。
这里重点看:
- 新版本实例和旧版本实例的 RT、错误率、CPU、线程占用差异
- 某一批新 Pod / 新节点是否先开始变差
- 同一时刻所有实例是不是几乎同时一起升高
两种很有代表性的分布
新实例更差,旧实例相对稳。
这通常很像发布回归。哪怕流量也在涨,只要新版本明显更贵,就说明承压能力变化不是均匀发生的。
所有实例几乎同时一起变坏。
这更像共享资源被一起推高了,比如数据库、缓存、消息堆积或上游流量整体放大。
但这里也要防一种假象:
- 新实例先慢一点
- 它先把数据库、缓存或下游拖高
- 共享资源一坏,旧实例后面也跟着一起坏
最后你看到的图像就像“全体一起慢”,可真正起点还是新版本把余量先吃掉了。
所以实例分布不能单独看,要和前面的时间线连起来看:到底是谁先差,谁是后来被拖进去的。
把三条线合起来,才能拆出“触发器”和“承压能力变化”
线上这类事故最常见的误区,是非要先给出一个单选答案:
- 要么是流量问题
- 要么是代码问题
但更接近真实现场的问法应该是:
- 触发器是什么:是流量上来了,还是某个依赖先抖了
- 承压能力为什么变差:是新版本更贵了,还是系统本来就接近边界
把这两个问题拆开,主次通常就顺了。
例如几种常见结论
结论一:流量是主触发器,单位成本没明显变。
这时优先级通常更偏扩容、限流、削峰、资源保护。
结论二:单位成本明显变贵,新实例更差,流量只是把问题提前暴露。
这时回滚或止损发布通常更靠前,否则你只是拿更多资源去喂一个更贵的版本。
结论三:发布先吃掉部分余量,流量再把系统推过线。
这类需要最克制的判断。因为它不是“谁全责”,而是“先止哪一头更能止血”。有时要先保流量面,有时要先处理版本面,但前提是主会场已经把这两层拆开了。
现场别写成会议,动作也别同时开太多条线
这里当然会涉及协同,但这部分不需要讲得太重。
只要记住一个很实用的原则:在时间线、单位成本、实例分布还没拼起来之前,不要同时把太多互相干扰的动作全开出去。
因为一旦你一边扩容、一边回滚、一边改参数、一边放重试,后面很容易根本看不清到底是哪一步在止血,哪一步在继续放大。
所以这类现场更像是在拆主次,不是在做会议纪要。
最后压成一句话
流量突增还是代码回归,别先急着选立场。
先沿着时间线看谁先动,再看单位请求成本有没有变贵,最后看问题是偏新实例还是全局一起坏。这样通常就能把“触发器”和“承压能力变化”拆开。
拆开之后,再决定先扩容限流还是先回滚,动作才不会打架。