首次响应包含额外的初始化开销,通常慢于稳态响应
别名: 冷启动 · 首次更慢 · first-response penalty
概念解释
同一按钮,今天第一次按,要建连接、拉模块、填缓存、跑鉴权;第五次按,这些都已经在。首次响应因此几乎总是带着一笔初始化开销(cold-start overhead),比之后的稳态响应慢一截。慢的不是「这个功能就是慢」,是「这一次在付入场费」。把首次和稳态当成同一种性能,会既解释不清用户的投诉,也优化错对象。
这条说的是响应(结果回来),不是第一次触摸的输入排队。输入排队是另一笔账。
机制
入场费来自一次性工作:TLS 握手、路由发现、代码分片下载、反序列化、空缓存上的全量查询、运行时编译。它们摊在第一次请求上,不摊在第二次。工程上常见的「平均响应时间」把第一次和后面九次放进同一个均值,首次被稀释,稳态被首次拖累,两头都不像。
开销还会跨入口传染。打开应用后的第一次「任何」网络请求,往往替整次会话付握手的钱;第一个打开的设置页,往往替整个设置包付下载的钱。所以「这个按钮慢」有时不是按钮的错,是它碰巧成了会话里的第一下。
怎么研究
把同操作的第 1、第 2、第 n 次分开报延迟,冷启动(杀进程、清缓存、新会话)与热启动交叉。看首次多出来的时间花在哪一层:网络握手、代码加载、还是业务查询。
自变量:是否冷启动、第几次调用、依赖模块是否已加载。 因变量:分段耗时(握手 / 下载 / 业务)、首次相对稳态的倍数。
实验室若在测之前先点一遍「准备」,首次开销会被测没。现场日志要用会话序号标记请求,否则平均值看起来永远「还行」。
边界
纯本地、无懒加载的界面,首次和稳态可以几乎一样,这条不明显。无服务器的一次性工具(计算器)没有入场费。服务端无状态但每次都要冷计算的任务(每次都跑大模型),每次都是「首次」,不存在稳态可比较。CDN 与边缘缓存会把「首次」变成「这个节点上的首次」,同一用户在另一座城市再付一次入场费。
怎么落地
- 性能报告把「会话内第一次」和「同会话后续」分成两列,不要只给混合平均。
- 排查「这个按钮慢」时先问是不是会话第一下;若是,去查握手和包加载,而不是按钮的业务逻辑。
- 能上移的入场费就上移:连接预热、关键分片打进首包,让第一下少付。
- 验证:杀进程后打开,立刻做目标操作,记下耗时;同一会话里再做四次。第一次应能指出多出来的那一截属于握手、下载还是查询。说不清这一截,就还在看混合平均。