首页 / m.itcdj.com / 正文

Serverless冷启动优化 落地时没人说的代价

上周跟一个做电商技术的朋友撸串,他说去年618零点刚过,后台监控突然跳出来一堆接口超时报警。查了快半小时,最后定位到是下单链路里的一个库存校验函数,刚好碰到冷启动。

用户点下单的瞬间,函数已经快一个小时没被调用过,平台早就把分配给它的计算资源回收给别的业务了。从调度器找资源、拉镜像、跑运行时初始化、加载他写在函数顶层的数据库连接逻辑,整套流程跑了3.2秒。搁谁谁不懵。

你以为的冷启动 其实是三层叠加的等待

说实话,很多人对冷启动的认知,从一开始就偏了。

冷启动的耗时从来不是单一环节造成的。最常被拿出来说的“拉镜像慢”,其实在现在的云厂商网络环境里,占比往往不到总耗时的30%。真正拖时间的,是前面两层:

第一层是平台侧的资源调度。你函数多久没跑了,平台为了不浪费算力,会把原本分配给你的容器、虚拟机资源收回去,分给其他有突发请求的业务。下次你要再调用,调度器得从整个资源池里,找一块匹配你函数规格、带对应运行时的空闲资源。这步快的话几百毫秒,赶上资源紧张的大促节点,等个两三秒太正常。

第二层是运行时与用户代码的初始化。比如你用Python写函数,光把解释器加载进内存、把依赖包里的第三方库全导入,就得几百毫秒。更别说很多人习惯把连数据库、初始化SDK、读本地配置的逻辑,写在函数的全局作用域里——这些代码只有在函数第一次启动的时候才会跑,但是每一次冷启动,都得完完整整跑一遍。

Serverless冷启动全链路耗时拆解示意图

我之前见过一个做内容审核的团队,函数全局作用域里直接初始化了三个不同厂商的内容审核SDK,光这部分代码的执行耗时就接近1.5秒。平时测试的时候没人在意,等到线上碰到冷启动,接口直接超时,才想着把这些初始化逻辑挪到请求处理逻辑里。结果挪完发现,每次请求都要跑一遍初始化,整体耗时反而涨了三倍。

常见优化手段的真实代价

现在搜Serverless冷启动优化,一搜一大堆教程,列出来的方法翻来覆去就那几个。但很少有人说,每个方法背后都是要付代价的。

最常用的手段是开预留实例。就是你跟平台说,给我固定留一块对应规格的资源,不管有没有请求,这块资源都不能收回去。这么做确实能把冷启动耗时压到几十毫秒,跟常驻服务的响应速度差不多。

预留实例的成本是按预留时长持续计算的,哪怕没有任何请求。之前有个做内部报表的团队,给一个月只触发三次的定时报表函数开了预留实例,三个月下来,光这个函数的预留费用就花了六千多。没人觉得不对,反正预算是总盘子里出的,但这事说穿了就是纯浪费——一个月跑三次的离线任务,哪怕冷启动等个五秒,也没有用户会感知到。

第二个常用手段是精简函数镜像。把原来动辄几百MB的基础镜像,换成只带最小运行时的精简版本,把没用的系统命令、冗余依赖全删掉。比如原来300MB的Node.js镜像,压到30MB,拉取时间确实能从1秒降到100多毫秒。但代价是什么?你得花大量时间测试,确保所有依赖都没漏,不会跑着跑着冒出来个“module not found”的报错。

精简前后Serverless函数镜像大小对比图
精简前后Serverless函数镜像大小对比图

还有最近几年各个平台都在推的快照方案。就是平台把函数第一次启动完成后的内存状态拍个快照,下次再碰到冷启动,直接把快照加载进来,跳过运行时初始化和全局代码执行的步骤。听起来很美对吧?

快照方案的适用边界比大多数人想的窄得多。比如你函数里初始化的数据库连接池、第三方服务的长连接,存到快照里之后,隔几个小时再加载,这些连接早就断了。你加载完快照,还得花时间重新建连,搞不好总耗时比原来的冷启动还高。而且快照服务本身是要额外收费的,不是包含在基础函数费用里的。

别为了消冷启动把架构搞歪了

麻烦的是,很多人做Serverless冷启动优化的时候,走着走着就忘了初衷。

Serverless的核心价值是什么?是不用管服务器,按需用按需付费。结果很多团队为了把冷启动压到零,给所有函数都开了预留实例,算下来每个月的成本,比原来直接买几台固定配置的虚拟机跑常驻服务还高。这就完全走偏了——你花了更大的成本,根本没享受到Serverless的弹性优势,只是换了个平台交资源费而已。

其实判断要不要花精力优化某一个函数的冷启动,标准特别简单:这个函数的响应,是不是直接被C端用户感知到的?

如果是,比如用户点个按钮就触发的接口、给用户返回页面内容的函数,那冷启动耗时超过200毫秒,用户就会觉得卡顿,值得花成本去优化。如果是后台跑的定时任务、离线数据处理、异步消息消费的函数,哪怕冷启动等个三秒,没有任何用户会盯着屏幕等结果,那你花一堆钱开预留实例、压镜像、买快照,纯粹是精力浪费。

别搞反了。

冷启动不是什么洪水猛兽。它本质上是Serverless平台为了帮你省成本,做的资源弹性调度带来的必然代价。你想完全消掉它,就得把弹性的好处全部还回去。

上个月那个做电商的朋友,最后没给库存函数开预留实例,只是把原来300多MB的镜像压到了40MB,把全局作用域里的数据库连接改成了按需初始化。现在这个函数的冷启动耗时从3.2秒降到了400毫秒,大促的时候用户根本感知不到卡,每个月的成本还比原来开预留实例的方案省了七成。