...
Back

冷启动是个定价决策,不是性能 bug

缩到零不是平台的属性,它是一个旋钮。把它留在默认值上,等于让别人替你决定了「最慢的那个请求」值多少钱。

冷启动是个定价决策,不是性能 bug

冷启动是个定价决策 ❄️

每一次 serverless 迁移里,总有一个下午是花在"让第一个请求变快"上的。瘦身镜像。懒加载重的模块。把数据库客户端从模块作用域挪出去。这些都是实打实的工作、也有实打实的收益,而且全都在优化错误的变量。

第一个请求慢,是因为刚才什么都没在跑。这不是性能 bug。这是你接受"缩到零"时点头同意的行为,而它明码标价 —— 你可以直接把钱付了。


你实际在交换什么

缩到零说的是:没人用它的时候不花钱,而把它叫醒的那个人承担启动成本。

对很多负载来说这确实是笔好买卖。内部工具。预发环境。一天触发九次的 webhook。任何用户就是你自己、或者两秒首响因为是后台请求而根本看不见的场景。

对一个产品的首页,这是笔坏买卖。不是因为两秒不可忍受,而是因为在付这两秒。吸收你冷启动的那个人,大概率是从某个链接过来的首次访客 —— 正是你花了最多钱换来、而且正在用最少的信息评估你的那批流量。成本是真的,而且落在最糟糕的位置。


先算账,再优化

有用的动作不是把启动变快,而是先搞清楚"保持一个实例常热"到底要多少钱 —— 因为这个数字常常小得荒谬,和你正准备投入的优化工作量完全不成比例。

粗略地:

常热基线 ≈ (实例内存 × 实例数) × 每小时费率 × 730

对一个只留一个常热实例的小服务,这经常落在每月个位数美元。拿它去对比你正要花掉的那个下午 —— 以及那些直接关掉标签页的访客。

这笔账之所以被跳过,是因为 min instances = 0 是默认值,而默认值感觉不像决策。但它恰恰就是决策,只不过是由写模板的那个人替你做的。


什么时候优化冷启动仍然是对的

花钱保持常热并不能消灭冷启动,只是让它变稀有。流量尖峰依然会拉起新实例,而新实例依然是冷的。所以启动路径值得关注 —— 只是不该是惊慌失措的关注。

真正有杠杆的改动,按顺序:

  1. 别在模块作用域里连任何东西。 在 import 时构造的数据库或缓存客户端,会让每一次冷启动都等一次握手 —— 包括尖峰期间、依赖方本来就已经吃力的那些次。
  2. 镜像做小。 拉取时间是启动时间的一部分。多阶段构建和裁剪过的输出格式在这里赚两次:一次在仓库成本,一次在延迟。
  3. 把重依赖推迟到需要它的那条路由。 如果一个很少被用到的端点拖进来一个巨大的依赖,每一次冷启动都在为它付费。
  4. 有意识地设置并发度。 单实例同时处理多少请求,决定了你多久拉起一个新实例。设太低,轻负载下就不停冷启动;设太高,一个慢请求会堵住它的邻居。

注意这些都到不了零。它们缩短的是尾巴。旋钮才是在常见情况下直接把它拿掉。


值得留下的那个视角

基础设施的默认值是"附带账单的主张"。缩到零、请求并发、实例上限、日志保留期 —— 每一个都是旋钮,每一个都由某人挑了个"对某些人合理"的值,而且它们都不会自报家门说"我是个选择"。

值得养成的习惯很小:对每一个你继承下来的默认值,能用一句话说出它花了你什么、改掉它又要花什么。不是要把它们全改掉,只是要知道 —— 这样下次一个慢的首响把你推向一整天的模块手术时,你能先确认一下:答案是不是一行配置加五美元。