上个月我们把一个跑在云函数上的订单回调接口切到了新的运行时环境,上线前压测一切正常,正式跑起来之后却发现一个很奇怪的现象:同一个接口,第一次被调用要等 3 秒左右,后面热起来的调用只要 80 毫秒,流量一掉下来,等待又回到 3 秒。当时我们怀疑是下游数据库慢,查了两天日志,最后发现既不是数据库也不是网络,锅在函数本身的启动过程上。
如果你也在排查类似的首调用延迟,或者想自己搭一套能快速拉起的运行环境,可以先看看这几家的机器规格和交付说明:digitalocean(Droplet 开发者云主机),数掘科技(弹性云服务器)
云函数这类按量计费的形态,本质上是把一段代码打包成一个可以随时启动、随时销毁的实例。平台平时不养着它,只有请求进来的时候才把它从"没运行"变成"正在运行",这个过程就是冷启动。理解了这一点,很多看起来玄学的现象就都有了解释。
冷启动到底慢在哪:拆成四段看
我拿一个最小化的函数做了埋点,把从请求进来到函数真正开始执行的这段路拆成四段:调度排队、镜像或代码包加载、运行时初始化、你的初始化代码(全局变量、连接池、SDK 客户端)。结果很有代表性:
调度排队大约 200 毫秒,代码包加载 300 多毫秒,运行时初始化 1.6 秒,剩下的 800 毫秒花在我们自己的初始化代码里主要是建立一个数据库连接池和一个 HTTP 客户端。热调用为什么只要 80 毫秒?因为这四段全部被跳过了,实例已经躺在内存里等着干活。

关键结论是:冷启动的耗时主要由平台的镜像体积和运行时版本决定,而你自己的初始化代码也是实打实的一部分。很多人优化时只盯着平台参数,忘了自己的初始化代码里藏着一个连接池预热。
第一招:把代码包瘦身,冷启动直接砍掉一半
我们那个函数原本带了整个 SDK 目录和一个没用到的图像处理库,打包之后 480MB。删掉无用依赖、换掉体积大的依赖版本之后,打包体积降到 96MB,冷启动时间从 3 秒掉到 1.4 秒。这一步几乎是零成本,收益却很直接:代码包越小,平台加载它就越快,这个规律在几乎所有 FaaS 平台上都成立。
有几个常见的坑:一是别把 node_modules 整个塞进去,用依赖锁定加按需安装;二是不要在包里带上测试数据和字体文件,它们可能比你的业务代码还大;三是留意解压后的实际占用,有的平台压缩前和压缩后差别很大。优化完之后记得在控制台看真实的包大小,别凭感觉。

第二招:把初始化代码从"每次都做"改成"只在必要时做"
冷启动时执行的全局代码,本质上是每次都要重跑一遍。很多人图省事,把连接池创建、证书加载、配置拉取全放在模块顶层。正确做法是懒加载:真正需要连接的时候再建,连接本身做超时和重试;把不需要每次新建的对象缓存起来;大对象的初始化推迟到第一次被访问。
我们把连接池改成懒加载 + 预热线程(后台建连接,不阻塞第一个请求),这 800 毫秒里的 600 毫秒就消失了。需要注意,懒加载必须有超时保护,否则第一次请求失败会连带影响后续所有请求。
第三招:给关键接口留一个"不冷"的实例
如果你的接口对延迟敏感(支付回调、登录鉴权这类),光靠优化启动时间还是不够稳,因为平台的调度和底层机器负载你控制不了。这时候可以给关键函数配置预置并发,也就是提前准备好几个常驻实例,请求进来直接命中热实例,不用等启动。
预置并发不是免费的,它按预留实例数持续计费。如果你的流量是尖峰型、平时调用很少,全天开着预置很不划算。更经济的方式是做一层自己的"保温":定时用一个极轻量的探针请求去触发函数,让它保持热状态,同时把真正的业务请求路由到已经就绪的实例上。

我们后来在网关层加了一个健康探测的定时任务,每分钟触发一次一个几乎不耗资源的 ping 函数,线上首请求的 P99 从 3.1 秒降到了 260 毫秒,账单每月多了不到 20 块钱。这笔账很好算。
第四招:不是所有接口都值得放在云函数里
我们复盘那两天的排查,最大的收获不是任何一条优化技巧,而是一个判断标准:调用频率高、延迟敏感、逻辑重的接口,其实不适合跑在按需拉起的模型里。这类接口放到常驻的轻量应用服务器或者容器实例上,行为更可预测,调试也方便,毕竟容器一启动就是一直在跑的。
这也是我们后来给团队定的规矩:先用一条链路的数据说话调用频次、平均耗时、对首包延迟的容忍度再决定是留在函数里还是搬到常驻服务上。别为了用新形态而用新形态,很多"函数化"改造最后是被运维复杂度拖垮的。

怎么确认自己遇到的是冷启动
最后说几个排查时的判断方法。第一,在日志里给每次请求打上实例标识,如果同一个实例的第一次请求明显慢、后续请求正常,那就是冷启动无疑。第二,看监控面板上的实例数和并发数,如果流量回来后实例数从 0 涨起来再掉回去,恭喜你找到了。第三,对比冷实例和热实例的耗时分布,两条曲线之间的差值就是你要优化的空间。
最后提醒一句,不要用本地测试的结果去推断云上的冷启动。本地跑得再快,也不会经历调度、代码包加载这些环节,本地测出来的数字对线上几乎没有参考价值,一定要以线上真实的首请求数据为准。
把这件事想明白之后你会发现,云函数冷启动其实不是平台的一个 bug,而是一种"用启动延迟换资源成本"的商业模式。理解了它,你的架构选型才能踩在点上。


喜欢
顶
难过
囧
围观
无聊



