Serverless这个词,说新不算新,说旧也不旧。但每次跟人聊起来,我发现多数人对它的理解还停留在“不用买服务器”这个层面,甚至有人直接问我:“搞个Serverless是不是等于白嫖云厂商的机器?”这种问题听多了,我反而觉得Serverless真正的价值被严重低估了。
这篇内容我不想复述官网文档,而是从“零成本按需计算”这个说法出发,拆一拆Serverless到底是怎么做到“按需”的,按的是什么“需”,零成本的情况下你能得到什么、又会失去什么。然后给出一套可以直接上手的部署路径,包括本地调试、线上配置、账单分析、冷启动和并发限制这些实战中一定会碰到的东西。
这篇内容适合三种人看:第一次接触Serverless的前端或后端开发、想把内部小系统迁到Serverless的运维同学、以及正在做技术选型但被各种概念绕晕的架构师。如果你已经有一些云上使用经验,读起来会更顺。
1. Serverless的本意是交付边界,不是“没有服务器”
1.1 先说我怎么理解“零成本”和“按需”
很多人在第一次听到“零成本按需计算”的时候,第一反应是:是不是像水电煤一样,用多少付多少,不用就不付?这个理解方向是对的,但细节上差得很远。
我自己的理解方式是把它和“租办公室”对比。传统服务器就像你租了一整层办公室,不管你实际坐了多少人,租金都是按整层算,装修、空调、保洁都要自己管。容器化就像租工位,按工位数量付费,但公共区域和管家还是得自己操心。而Serverless更像是你在共享办公空间里按小时租一个会议室,约了就用,用完就走,水电、空调、清洁全都是物业的事,你只关心会议开得顺不顺。
这个类比能解释Serverless几个核心特征:
- 不用关心基础设施:CPU、内存、网络、磁盘、补丁、升级,这些都不是你的事。
- 按实际使用付费:不是按“你预留了多少资源”付费,而是按“你实际跑起来的资源量”付费。
- 天然拥有弹性:一个请求和十万个请求,对使用者来说不需要提前预估容量。
但这也意味着,Serverless的“零成本”从来不是“免费”,而是“没有最低消费”。这一点是整个话题的起点,理解不了这个,后面看账单的时候会发现很多意想不到的东西。
1.2 平台和用户之间的权责划分
用最简单的话说,Serverless把一个应用的运行拆成了两层:一层是平台负责的,包括基础设施、弹性伸缩、高可用、故障恢复;另一层是用户负责的,包括业务代码、依赖环境、状态管理、配置、以及成本控制。
我常用一张表来区分传统部署和Serverless的权责:
| 关注点 | 传统虚拟机 | 容器平台 | Serverless/FaaS |
|---|---|---|---|
| 基础设施 | 自管 | 平台管 | 平台管 |
| 运行时 | 自管 | 基本自管 | 平台管 |
| 弹性扩容 | 手动或脚本 | 自动,但需配置 | 平台自动 |
| 计费单位 | 实例数+时长 | 实例数+时长 | 调用次数+资源量+流量 |
| 最低消费 | 有 | 有 | 无 |
| 冷启动 | 无 | 无 | 有 |
| 超时上限 | 随你 | 随你 | 平台限制 |
这张表的价值在于,它告诉你Serverless不是“免费白嫖”,而是“转移了责任”。你不需要为99.99%的高可用兜底,也不需要为闲置时间付费,但你要接受平台给你设下的边界——超时上限、并发上限、临时磁盘大小、代码包体大小限制。
所以真正要学的第一课不是怎么写函数,而是知道哪些事平台替你扛了,哪些事平台不替你扛。后面讲到的部署、成本、踩坑,全都是围绕这张表展开的。
2. 第一次Serverless部署:以函数计算为例跑通全流程
2.1 从初始化到本地开发
这里我用目前最通用、资料最多的函数计算服务作为例子。整个流程可以先本地开发再部署,也可以直接在控制台写代码,但我的建议是从一开始就走本地开发+命令行部署的路线,因为后面更新版本、回滚、多环境配置都会方便很多,也更容易用Git管理。
第一步是准备项目目录。一个标准函数项目的结构大概是这样:
my-serverless-app/ ├── src/ │ ├── index.py # 函数入口 │ └── requirements.txt # 依赖清单 ├── serverless.yml # 部署配置文件 └── .env.development # 本地环境变量第二步是写一个最简单的接口。以Python为例,入口函数通常长这样:
import json def handler(event, context): body = {"message": "hello from serverless"} return { "statusCode": 200, "headers": {"Content-Type": "application/json"}, "body": json.dumps(body) }这个函数的输入event里包含HTTP请求信息、触发器上下文,输出是一个标准HTTP响应结构。不同运行时写法会有差异,但基本思路一致:平台把请求包装成event传给你,你返回一个可序列化的结果。
2.2 配置触发器:让函数能被外部访问
写好的函数不会自己暴露成URL,需要配一个HTTP触发器。这里我用serverless.yml来声明:
service: my-serverless-app provider: name: <cloud-provider> # 替换成你选的云厂商 runtime: python3.10 region: <your-region> functions: hello: handler: src/index.handler events: - http: path: /hello method: get这段配置的意思是:创建名为hello的函数,运行环境是Python 3.10,把src/index.py里的handler方法作为入口,同时创建一个HTTP GET接口,路径是/hello。
这里有一个关键点:触发器是函数和外部世界之间的桥梁。没有触发器的函数只能被内部调用,有了HTTP触发器才变成一个真正的API。同一个函数可以挂多个触发器,比如HTTP触发器、定时触发器、消息队列触发器。我实际项目中用得最多的就是HTTP触发器和定时触发器,前者接请求,后者跑定时任务。
2.3 部署命令和第一次请求
在项目根目录执行部署命令:
serverless deploy正常情况下它会做几件事:打包上传代码、创建或更新函数、创建触发器、输出访问地址。成功后的输出类似这样:
Service: my-serverless-app hello: https://xxxxxx.cn-hangzhou.fcapp.run/hello然后我用curl打一下这个地址:
curl -w "\n总耗时: %{time_total}s\n" https://xxxxxx.cn-hangzhou.fcapp.run/hello我第一次打出这个请求时,终端里显示“总耗时: 1.2s”,而函数里根本没有复杂计算。这是因为第一次请求触发了冷启动,平台需要临时拉起运行环境。第二次再请求,耗时就降到几十毫秒。这个1秒级别的差异,是Serverless最经典的第一次体验,也是后面所有优化故事的开头。
到这里,一个最小可用的Serverless服务就算上线了。但别急着庆祝,接下来才是真正让我长记性的部分——账单和那些平台限制。
3. “零成本”账本:免费额度、按量计费与三种典型账单
3.1 免费额度到底怎么算
大多数主流FaaS平台都有一条“每月免费额度”的规则,这也是“零成本”说法的来源。但免费额度往往不是一个数字,而是三个或更多数字的组合。我带团队的时候发现,很多刚接触的人只知道“有免费额度”,却不知道免费额度分维度。我整理成一张表:
| 计费维度 | 免费额度量级 | 超出后计费粒度 |
|---|---|---|
| 调用次数 | 每月100万次左右 | 按万次计费 |
| 资源使用量(GB-秒) | 每月40万GB-秒左右 | 按GB-秒计费 |
| 外网出流量 | 每月100GB左右 | 按GB计费 |
| 公网IP、固定带宽等增值服务 | 通常不计入免费额度 | 按配置计费 |
“资源使用量”这个概念很多人第一次看到会蒙。它是内存大小和运行时间的乘积:一个函数配置了1GB内存,运行了1秒,就消耗1GB-秒;配置512MB内存运行2秒,也是1GB-秒。这个单位把“内存”和“用时”合成一个成本指标,平台按它来算你占用的计算资源。
3.2 一个小型API的真实成本推演
假设我要部署一个个人博客的访问计数接口,每天被调用500次,每次平均内存256MB,平均运行时间100ms,外网出流量很小,一个月流量约50GB。
- 调用次数:500 × 30 = 1.5万次,远低于100万次免费额度。
- 资源使用量:1.5万 × 256MB × 0.1s = 38.4万MB-秒,换算成GB-秒是375GB-秒,低于40万GB-秒免费额度,依然免费。
- 外网出流量:50GB,低于免费额度。
所以在免费额度内,这个接口的实际月成本是0元。这也是“零成本”最真实的一种解释:不是没有成本,而是成本低于计费阈值时收不到钱。
3.3 三种容易把账单打爆的情况
免费额度听上去很美,但我在实际使用里见过不少账单翻车的案例,归纳起来有三种:
循环调用。一个函数在处理失败后直接重试自己,没有退避策略,形成死循环。有一次我见过一个函数在半天内被调用了6000万次,直接把免费额度打穿,账单从0变成一千多元。从那以后我就养成了一个习惯:所有带重试逻辑的函数,必须设置最大重试次数。
大内存配置。把函数内存从512MB调到2048MB的人,往往只想着“跑得快一点”,忘了资源使用量是内存乘以时间,内存变成4倍,同样的调用次数成本直接变4倍。很多重型依赖确实需要增大内存,逻辑上没错,但免费的额度会更快消耗完,而且如果你的初始化逻辑里有并发连接,还会放大冷启动时的资源占用。
外网流量低估。函数访问数据库、调用第三方API、给用户返回大文件,这些都会产生外网出流量。个人项目的免费额度通常够用,但一旦开始做文件上传、图片处理,出流量会远超预期。我有个项目就是给用户生成PDF,单个文件2MB,本来没什么感觉,结果做了个群发功能,一个月流量直接跑到200GB以上。
这里我特别想强调一点:Serverless的成本管理本质上是对一个函数一个函数做“内存、调用频率、执行时间”三维建模。上线一个函数之前,先估算这三个值,再和免费额度对照一下,就知道它到底会不会花钱。如果你在写代码阶段就已经知道某个函数是热点,那就要在设计阶段考虑清楚,是走消息队列削峰,还是接受它的账单。
4. 冷启动、超时与并发:Serverless翻车高发区实测
4.1 冷启动到底有多“冷”
冷启动是Serverless最独特的体验,也是从传统服务器转过来的开发者最不适应的点。前面我已经说过,第一次请求耗时1.2秒而第二次只要几十毫秒,这个差距就是冷启动造成的。
冷启动的过程大致是:平台收到请求后,如果发现没有可用的实例,就要拉起一个新容器,把运行时环境准备好,再加载你的代码包,最后执行你的初始化逻辑。这个过程消耗的时间,可以拆成四部分:
| 环节 | 典型耗时(经验值) |
|---|---|
| 调度和容器拉起 | 50-300ms |
| 运行时启动 | 100-500ms |
| 代码包下载和解压 | 100-500ms |
| 代码初始化逻辑 | 取决于你的写法 |
这四段加起来,一个Java或Node.js函数的冷启动时长冲到2到5秒都不奇怪。Python和Go相对快一些,但不会完全消失。对于用户可感知的接口来说,2秒足够让体验明显变差。
缓解冷启动的手段,业界有一套比较成熟的组合拳:
- 设置最小实例数(预置实例)。平台保持几个实例常驻,用“预热”换“首字节时间”,成本会增加。适合对延迟敏感的正式业务,不适合零成本项目。
- 精简依赖和代码包。包越小,下载和解压越快。有些Node项目光node_modules就有几十MB,冷启动时间直接被拖慢。
- 把初始化逻辑放到函数外部。全局变量、数据库连接池、配置加载只执行一次,能被多个请求复用。
- 选择合适的运行时。Java、C#的启动开销天然比Python、Go大,选型时要考虑清楚。
4.2 超时和并发限制:平台给你划的红线
传统服务器上一个进程跑多久都行,但Serverless不一样:每个平台都对单次函数执行设置了超时上限,常见默认是10秒,最大可调到你选的区间;同时还有并发上限,默认一个账号下的并发实例数往往在100到1000之间。
这意味着两件很重要的事:
- 如果你的代码里有长轮询、长时间批量任务,或者上游接口不稳定,函数很容易超时被强制终止。
- 如果短时间涌入大量请求,超过并发上限,新的请求不会被排队等待,而会直接报限流错误。平台宁可返回失败,也不肯把你的请求堆在队列里拖垮后面所有人。
这里顺便说一句,很多人以为Serverless的弹性是无限的,其实不是。弹性是有边界的,边界就是平台给你的并发配额。弹性真正厉害的地方在于:从1个实例扩到100个,可能只要几秒钟,这在传统运维里几乎不可想象。
4.3 一次并发突刺的完整排查过程
我印象很深的一次事故,是给某个活动做一个报名接口。活动预告那天晚上流量一下子冲上来,接口开始大量返回429限流错误。我当时在第一时间确认了三件事:
第一步:打开函数监控面板,看调用次数和错误分布。调用次数确实瞬间飙高,错误类型里大部分是“并发限制”。
第二步:看日志,确认不是代码本身的问题。日志里业务异常很少,大量是平台层面的限流拒绝。
第三步:查当前并发配额。发现账号默认配额是100,而活动瞬时QPS到了300,每个请求即使只跑200ms,也需要60个并发实例,理论上100个并发是够的,但平台会预留一部分给其他函数,实际可用的并发没有100。在平台上把该函数的并发上限调高到300后,请求很快恢复。
那次之后,我把所有和活动相关的函数都加上了“压测+配额评估”的步骤,并且把一张记录函数并发、内存、超时的配置表写进了项目文档。这个配置表其实就三列:函数名、预估峰值QPS、所需并发实例数。算并发实例数的公式也很简单:峰值QPS乘以平均执行时间(秒),再留1.5倍的余量。
5. 哪些服务不适合Serverless:我的选型判断清单
5.1 不适合的典型场景
Serverless不是万能药。有些代码放上去,不仅没法省钱,还会额外增加维护负担。我总结了几类:
长时运行任务。比如视频转码、大批量数据清洗、每天跑半小时以上的定时任务。这些任务要么超过函数的超时上限,要么必须拆成一个个小切片,用消息队列驱动多次执行,架构复杂度会明显上升。
对延迟极度敏感的服务。在线游戏房间匹配、高频交易、实时音视频信令,这类服务对P99延迟有严格指标,冷启动和平台调度带来的抖动很难接受。虽然可以通过预置实例缓解,但预置实例几乎等于让平台帮你养着常驻资源,成本优势就没了。
有状态服务。WebSocket长连接服务、分布式session集中的业务,状态放在内存里会随着实例销毁而丢失,必须引入外部的Redis或数据库,又增加了网络开销和运维复杂度。
GPU推理等重型计算。FaaS的计费和控制面都偏向短任务,绑定GPU资源的实例往往不便宜,而这类任务动辄跑几分钟,直接用GPU虚拟机可能更划算。
5.2 适合的典型场景
反过来,下面的场景我是比较推荐Serverless的,也是我自己用得最多的:
API后端和微服务。轻量的HTTP接口,天然适合按请求计费的模式。结合API网关,一个完整的后端服务可以做到零常驻成本。
消息处理。接收消息、做过滤、转发、简单计算,这类任务执行时间短、频率波动大,用Serverless非常顺。
定时任务。每天定时抓取数据、发通知、做报表,量不大但需要稳定执行,Serverless的定时触发器能省掉一台常驻服务器。
事件驱动类。对象存储上传后触发图片压缩、数据库变更后触发缓存刷新,Serverless是这类场景的标准解。
原型和内部工具。个人项目、小团队内部的管理后台接口、实验性功能,快速验证,成本几乎为零,是我最喜欢用的场景。
5.3 我的一套判断流程
我把这套选型经验固化成了一张自查清单,每次接到“要不要上Serverless”的问题都先过一遍:
| 问题 | 适合用Serverless(答案为“是”时) | 不适合用Serverless(答案为“是”时) |
|---|---|---|
| 业务是请求或事件驱动的吗? | 是 | —— |
| 单次执行时间在几分钟内吗? | 是 | —— |
| 流量波动大吗? | 是 | —— |
| 可以设计成无状态吗? | 是 | —— |
| 对P99延迟要求低于几百毫秒? | —— | 是 |
| 依赖长连接或有状态会话? | —— | 是 |
这个清单不是严格公式,但绝大多数场景跑一遍就能得出比较清晰的方向。拿不准的时候,我会先写一个最小Demo上云跑一周,看实际耗时、错误率和账单,再决定要不要把整个业务迁过去。让数据替你做决定,比听任何人拍胸脯都靠谱。
6. 开发调试与可观测性:本地模拟、日志和链路追踪
6.1 本地开发和调试
部署到线上之前,最好能本地跑通。现在大多数FaaS平台都有官方的本地模拟工具或Serverless Framework插件,可以模拟event、context,并在本地启动HTTP服务。
以本地起服务为例,一条命令就可以跑起来(具体命令取决于你使用的框架,这里给出最常见的形式):
serverless dev它会启动一个本地HTTP服务,把serverless.yml里声明的函数和路由都模拟出来。你可以用Postman或curl打本地接口,和打线上几乎一样。区别是本地不会被平台限流,也不会被真实的触发器消息驱动,所以只适合做代码逻辑的快速验证。
本地调试还有一个很实用的技巧:本地跑起来之后,先用一个假数据把每个分支都覆盖一遍,包括正常路径、参数缺失、异常分支、超时分支。在Serverless里,因为函数执行环境和线上是有差异的,依赖装错、路径写错这类问题非常常见。本地能查出来的问题,就不要浪费一次线上部署的时间。
6.2 日志:Serverless最容易被忽视的坑
在传统服务器上排查问题,第一反应是ssh到机器上看日志。Serverless没有机器这个概念,日志是以函数为单位汇聚到日志服务的,所以你的第一反应应该是“这个函数的日志在哪个日志库”。
日志查询最常用的几个维度是:
- 按函数名过滤,看某个函数的所有日志。
- 按requestId过滤,看单次请求从进入到返回的完整日志。
- 按关键词过滤,比如“ERROR”、“Exception”。
这里一定要养成一个习惯:你的代码里必须打印requestId。平台一般会把requestId放进context或者环境变量里,你把它打到每一条日志里,排查的时候才能把一次请求的多条日志串起来。否则日志就是一盘散沙,几百条并发请求混在一起,根本没法看。
6.3 可观测性三板斧
日志只是最基础的一层。函数计算服务通常会自带监控面板,能看到调用次数、错误数、平均耗时、资源用量等核心指标。除了这些,我强烈建议补上三样东西:
- 告警。给错误率、调用量、资源使用量设置告警阈值。零成本项目的告警尤其重要,因为免费额度用完就开始计费,不告警很可能下个月账单劝退。
- 链路追踪。如果一个函数背后调用了数据库、Redis、第三方HTTP API,最好接入分布式链路追踪。很多FaaS平台已经内置了和自家链路追踪产品的打通,配置一下就能看到整个调用链的耗时分布。
- 成本监控。所有云服务商都有账单和成本分析,把每个函数的费用打上标签,按标签汇总成本。这样每个月复盘的时候,一眼就能看出哪个函数在悄悄花钱。
最后分享一个我个人的小习惯。每次新建一个Serverless项目,我会在项目里放一个cost.md文件,记录每个函数的预估调用量、内存配置、执行时间、免费额度用量,以及实际上线后的真实数据。刚开始可能觉得麻烦,但只要经过两三次活动流量的冲击,这个文件的价值会体现得非常直接。因为它不只是账本,更是一个决策依据:下次同样场景出现的时候,你是选Serverless还是选一台小虚拟机,几分钟就能判断出来。
Serverless的“未来感”,不是因为它号称能零成本,而是因为它把计算真正变成了一个按用量收费的商品。作为开发者,我的态度是:别急着把它捧上神坛,也别急着否定它。拿出一个小项目,用一两个星期真实跑一跑,看看自己的业务到底适不适合这种模式,比任何人的经验都更有说服力。