Serverless 云函数这三年从一个”听起来很未来”的概念,变成了很多团队生产环境里的标配。它既在某些场景里把我们的交付速度拉满,也在另一些场景里悄悄吃掉了预算、拖慢了调试。本文用三年踩坑与救人经验,复盘 Serverless(主要指 FaaS 加托管 BaaS)到底省了什么、坑在哪里、成本怎么算,以及它和容器 / K8s 到底该怎么选。
一、Serverless 到底”省”了什么
Serverless 字面意思是”无服务器”,但服务器当然还在,只是不再由你管。它真正省下的是三件事:
- 省运维:不用关心操作系统补丁、运行时升级、扩缩容策略,平台替你兜底。
- 省闲时成本:按调用次数与运行时长计费,0 流量就意味着 0 费用,没有为”万一有人来”预留的空闲资源。
- 省伸缩心智:突发流量来临时自动横向扩展,你不必提前规划容量峰值。
但”省”的代价同样真实:你失去了对运行时环境的完全控制,冷启动、厂商锁定、调试困难会随之而来。理解这一点,才能避免把 Serverless 当万能药。
二、真香场景:事件驱动与突发流量
最契合 Serverless 的是”请求来了才跑、跑完就走”的事件驱动型负载:Webhook 处理、图片 / 文件转码、定时清理任务、轻量 API、边缘渲染。这类负载流量不规则、峰值高但均值低,按量付费的优势被放大到最大。
下面是一段 Cloudflare Workers 边缘函数示例,它只在特定路由上触发函数、其余请求直接回源,平时几乎不产生费用:
export default {
async fetch(request, env) {
const url = new URL(request.url);
// 只在 /api/ 开头的路由上触发函数,其余请求回源
if (url.pathname.startsWith('/api/')) {
return Response.json({
msg: 'hello from edge',
region: env.CF_REGION ?? 'unknown',
ts: Date.now(),
});
}
// 非 API 请求直接回源,函数几乎零成本
return fetch(request);
},
};
这种”薄边缘函数 + 回源”的模式,把函数当作智能路由层,是典型的真香用法:平时不花钱,峰值来了一秒顶上。
三、真坑场景:长耗时、稳态高并发、调试地狱
Serverless 也有它明显不擅长的地方,踩进去就是坑:
- 冷启动:Java、Python 带大依赖的函数冷启动可达数百毫秒到数秒,直接打挂对延迟敏感的接口。
- 超时与内存上限:主流平台单次执行有上限(例如 AWS 15 分钟、部分边缘平台仅 30 秒),长任务必须拆片或换方案。
- 本地调试困难:本地模拟与云端运行时总有差异,日志分散,分布式追踪要额外接入。
- 厂商锁定:函数触发源、权限模型、特有 SDK 各不相同,迁移成本往往被严重低估。
适合 / 不适合 Serverless 的对照
| 维度 | 适合 Serverless | 不适合 Serverless |
|---|---|---|
| 流量特征 | 稀疏、突发、峰值高 | 长期稳态、高并发常驻 |
| 延迟要求 | 容忍百毫秒级冷启动 | 要求稳定 <50ms 的强实时 |
| 执行时长 | 秒级以内的短任务 | 分钟级以上的长任务 |
| 状态管理 | 无状态、可幂等 | 重度依赖本地内存 / 连接池 |
| 典型例子 | Webhook、转码、定时任务 | 长连接网关、大模型推理常驻 |
四、成本账:看起来便宜,算起来未必
Serverless 的账单有两个容易被忽视的坑:一是”按量”在稳态高并发下并不比常驻容器便宜;二是出网流量、API 网关调用次数、日志存储都会单独计费。一个日均百万次调用、每次 512MB / 200ms 的 API,月度函数费可能看着不高,但叠加网关与流量后,未必优于一台预留实例。
下面是一个 AWS Lambda 的 Python handler 示例,配合 API Gateway 代理集成:
import json
def lambda_handler(event, context):
# event 由 API Gateway 代理集成注入
# context 提供运行时元数据
body = {
"message": "processed by lambda",
"request_id": context.aws_request_id,
"remaining_ms": context.get_remaining_time_in_millis(),
}
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps(body),
}
写好 handler 只是第一步,真正的成本控制在并发上限(reserved concurrency)、内存档位与批量处理上。把单函数内存从 128MB 调到刚好够用,往往能同时降低时延与账单。
五、与容器 / K8s 怎么选
很多新手把 Serverless 和容器对立起来,其实它们更多是互补。我们此前系统讲过 Kubernetes 生产实战 与 Docker 容器化,结论很明确:
- 长期运行、常驻连接池、稳定流量 → 容器 / K8s 更省心,成本可预测。
- 突发、事件驱动、流量稀疏 → Serverless 更便宜、上线更快。
- 混合架构最常见:核心服务跑容器,边缘 / 异步任务交给函数,各取所长。
六、落地建议与 CI/CD
如果你决定上 Serverless,这几条能少走弯路:
- 用 IaC(Terraform、Serverless Framework)声明函数,避免控制台手工点出来的”雪花配置”。
- CI/CD 自动部署:PR 预览环境、主干发布,参考我们的 GitHub Actions 自动化部署 实践。
- 加结构化日志与分布式追踪(OpenTelemetry),别等线上出问题才补可观测性。
- 设并发上限与告警,防止函数被刷爆导致账单失控。
七、冷启动优化:把延迟打下来的几招
如果你的场景确实绕不开 Serverless,又对延迟敏感,这几招能把冷启动压到可接受范围:
- 精简依赖:只装运行时真正 import 的包,用打包工具(如 esbuild、webpack)做 tree-shaking;Python 侧尽量用标准库或轻量依赖,避免把整个 pandas 打进函数包。
- 预热 / 预置并发:AWS 的 Provisioned Concurrency、阿里云函数计算的预留实例,本质是”提前付钱养着热实例”,用成本换稳定延迟。
- 更轻的运行时:Node.js、Go、Rust 的冷启动普遍优于 JVM 系;如果业务允许,把延迟敏感路径迁到轻运行时,收益立竿见影。
- 实例复用:把数据库连接、HTTP 客户端等初始化逻辑放在 handler 之外,利用函数实例的复用窗口,避免每次调用都重建连接池。
需要提醒的是,预置并发会削弱”按量付费”的成本优势,所以它本质是性能与预算的权衡,而非免费午餐。先用压测拿到真实的 P99 延迟,再决定要不要为冷启动付费,别凭感觉提前买单。
Serverless 不是银弹,也不该被妖魔化。它的价值在于把”不常跑的东西”的成本压到极致,把运维复杂度转移给云厂商。三年下来我的结论是:把函数用在它擅长的事件驱动与边缘场景,把它从它不擅长的高稳态长任务里请出去,你就能既享受真香、又躲过真坑。




