FunctionGraph 冷启动优化实战:把 3 秒压到几百毫秒
一、冷启动慢,先别急着改代码
函数冷启动偶尔超过 3 秒,第一反应往往是"代码写得慢"。但冷启动其实由几段拼成,不拆开就无法对症下药:
请求进入网关 → 调度并拉起运行时 → 下载/解压代码包 → 运行时进程就绪 → 执行模块级初始化 → 调用 handler。
其中"调度 + 拉包 + 运行时就绪"属于平台侧,而"模块级初始化"由你的代码决定。要优化,先量出各段占比。
二、两段打点法,十分钟拆清快慢
1. 拆"调度阶段"
- 在 handler 第一行打一条带
requestId和时间戳的日志; - 用网关/调用日志记录的请求进入时间减去该日志时间,差值就是调度 + 拉包 + 运行时就绪的耗时。
- 差值明显偏大(比如 > 1s)→ 瓶颈在拉包/调度,重点查代码包体积与镜像拉取。
2. 拆"初始化阶段"
在初始化代码里分段打点:读环境变量、建数据库/Redis 连接池、加载模型或大字典,各打一条时间戳日志。
- "handler 首行时间 - 初始化开始时间" = 初始化执行耗时;
- 哪两段打点之间差值大,慢点就在那里。
三、对症优化:三条主线
1. 初始化慢 → 把工作挪到模块级
Python 的模块级代码只在实例创建时执行一次,同一实例的后续请求会复用。因此把连接池创建、模型/词表加载、大字典构建都放到 handler 之外,不要每次调用都重建。
但要注意:实例存活时间没有承诺,连接可能已被回收。连接池务必加探活(取连接前 ping,或类似 pool_pre_ping 机制),否则会出现偶发的"连接已断开"报错。
2. 拉包慢 → 给代码包和模型"减负"
- 瘦身:第三方库常带测试数据、多架构
.so、文档,只保留运行时真正用到的部分; - 模型外置:模型文件放对象存储,初始化时按需下载到
/tmp并缓存(注意/tmp有大小限制,实例销毁即失效); - 改用自定义镜像:镜像层拉取通常比"下载 zip + 解压 + 安装依赖"更快,也更稳定。
3. 资源受限 → 适当调大内存
FunctionGraph 的 CPU 配额随内存规格提升。解压、初始化等步骤是 CPU 密集型,把规格从 512MB 提到 1024MB 再对比冷启动耗时,往往能降 20%~30%。
四、兜底:把冷启动"消掉"
如果业务对首包延迟敏感且能接受常驻成本,配置预留实例(预置并发)可直接消除冷启动。另外要注意区分:函数超时与 HTTP 网关侧超时是两回事,网关侧通常更短,别让用户等太久。
五、小结
优化冷启动的正确姿势是"先测量、再归因、后优化":用两段打点把调度/拉包与初始化分开,再针对性地挪初始化、瘦包体、调规格。没有测量就调参,多半是白忙。
- 点赞
- 收藏
- 关注作者
评论(0)