
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的“未来感”不是因为它号称能零成本而是因为它把计算真正变成了一个按用量收费的商品。作为开发者我的态度是别急着把它捧上神坛也别急着否定它。拿出一个小项目用一两个星期真实跑一跑看看自己的业务到底适不适合这种模式比任何人的经验都更有说服力。