Serverless 架构实践
Serverless 让你只管写代码、不管服务器,但它的无状态/冷启动/计费模型带来新约束。本文讲清 Serverless 的核心(FaaS + BaaS)、适用场景(事件驱动/突发/低流量)、代价(冷启动/供应商锁定/调试难),以及什么该用、什么不该用。
本文要点
- 主题聚焦:DevOps
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
我帮一个创业团队把一个内部工具从 ECS 迁到 Lambda,部署那天老板看完账单直呼"真香"——从每个月 800 块的常驻实例,掉到一个月 30 块按调用计费。两周后业务上线,真正的考验来了:第一次请求总是慢个两三秒,数据库连接数莫名其妙被打爆,本地怎么都复现不了线上那个偶发 bug。这篇文章把 Serverless 的核心、优势、代价一次讲透,让你在"上车"前就知道哪里有坑。
一、Serverless 到底是什么:FaaS + BaaS
很多人把 Serverless 等同于"云函数",这只说对了一半。Serverless 是两层组合:
- FaaS(Function as a Service,函数即服务):你写一个函数,云厂商负责把它跑起来、伸缩、计费。AWS Lambda、Vercel Functions、Cloudflare Workers、阿里云函数计算都属于这一类。你不碰服务器,甚至不碰进程,只管"事件进来 → 函数跑 → 返回"。
- BaaS(Backend as a Service,后端即服务):把数据库、对象存储、认证、消息队列这些后端能力变成托管的 API。Supabase、Firebase、DynamoDB、S3、Cognito 都是 BaaS。
真正的"无服务器",是 FaaS 负责跑你的代码、BaaS 负责扛状态和存储,两边都按用量计费、都自动伸缩。本质变化只有一个:你不再为"机器"付费,而是为"执行"付费。没有流量的时候,函数根本不存在实例,计费归零——这是它和传统云主机最大的区别。
一句话:Serverless 不是没有服务器,是服务器不再是你操心的事。
二、它真正的优势:免运维、按需付费、自动伸缩
Serverless 不是银弹,但它解决的三件事是实打实的:
- 免运维:没有机器要打补丁、没有操作系统要升级、没有 SSH 进不去的凌晨三点。安全更新、容量规划、可用区分布全是云厂商的事。对一个三五个人的小团队,这省下来的是一个专职 SRE 的工资。
- 按需付费:传统实例 7×24 跑着,半夜没流量也在烧钱。Serverless 按"请求数 × 执行时长 × 内存"计费,没流量不花钱。一个一天才几十次访问的后台 API,迁过去账单能砍一个数量级。
- 自动伸缩(含缩到零):流量从 1 RPS 涨到 10000 RPS,云厂商自动并发起函数实例;流量退下去,实例自动回收。不需要写 HPA、不需要预留 buffer、也不需要为"万一火了"提前买机器。
这三点叠加,让 Serverless 成为低流量、突发流量、事件驱动场景的性价比之王。
三、代价:冷启动、时长限制、无状态、锁定、调试难
优势的另一面是五条硬约束,每一条都够你喝一壶:
- 冷启动:函数空闲一段时间被回收,下一个请求进来要重新拉镜像、起运行时、加载代码。Node/Python 通常几百毫秒,Java/JVM 动辄几秒。这就是开头那个"第一次请求慢两三秒"的根因。冷启动是 Serverless 的原罪,优化方向只有几个:精简依赖、缩小打包体积、用 provisioned concurrency 预热、选更轻的运行时。
- 执行时长限制:Lambda 单次最多 15 分钟,Vercel 默认 10 秒(可升到 5 分钟、流式到 800K 上下文)。长任务根本塞不进一个函数,视频转码、大批量数据处理得切片或者改用 Step Functions / 队列 + worker。
- 无状态:每次调用可能落在不同实例,函数内的全局变量、内存缓存、本地文件不能跨请求信赖。状态必须外移到 Redis、DB、对象存储。习惯了常驻进程里
const cache = new Map()的人,这里会反复翻车。 - 供应商锁定:从 Lambda 迁到 Cloudflare,不是改个 SDK 就完事——触发器、IAM、事件格式、部署工具全是厂商私有的。上了 Serverless 就要做好"换厂商成本很高"的心理预期,把业务逻辑和厂商 SDK 隔离干净是唯一缓解手段。
- 调试和本地开发难:
serverless-offline之类的工具只能模拟个大概,IAM 权限、触发器联动、网络配置在本地几乎复现不了。线上排查要靠 CloudWatch / 日志,链路一长就抓瞎,分布式追踪(Trace)在 Serverless 里不是可选项,是必需品。
四、什么时候该用:事件驱动、突发、低频、API 后端
代价讲清楚了,但 Serverless 在这几类场景里几乎是默认答案:
- 事件驱动:webhook 回调、S3 上传后生成缩略图、CodePush 推送后触发构建、Stripe 收款后写流水。事件来了跑一下,跑完就消失,这正是 FaaS 的天然形态,用常驻服务去等一个一小时一次的事件才是浪费。
- 定时任务:每天凌晨跑一次数据汇总、每小时清理一次过期 session。
cron触发一个函数,比养一台 cron 机器干净得多。 - 突发流量:秒杀、营销活动、推文带量。Serverless 自动伸缩,扛得住瞬时高峰,活动结束自动缩到零,不用为 5 分钟的流量买一天的机器。
- 低频低流量:内部后台、管理工具、Demo 环境。一天没几次访问,按调用计费比常驻实例便宜一个数量级。
- API 后端:配合 Next.js / SvelteKit 这类全栈框架,Vercel / Netlify 把每个 API route 编译成函数,前端静态、后端函数,一栈到底。
五、什么时候别用:长连接、常驻、低延迟、重计算
反过来,这几类场景上 Serverless 就是自找麻烦:
- 长连接(WebSocket / SSE / gRPC streaming):函数是请求-响应模型,跑完就退,撑不住长连接。要做实时推送要么用专门的托管服务( API Gateway WebSocket、Pusher、Ably ),要么老老实实常驻服务。
- 常驻服务:消费 Kafka 的 worker、订阅 Redis pub/sub 的 listener、维护内存态的聊天网关——这些必须进程不死,和"跑完就退"的函数模型天然冲突。
- 高稳定低延迟:冷启动的几百毫秒到几秒抖动,在 P99 SLA 要求 50ms 的核心交易系统里不可接受。
- 重计算:机器学习训练、大规模视频转码、批处理 ETL。时长限制和计费模型会让账单比租 GPU 实例还贵,且根本跑不完。
判断标准很简单:这个服务"必须一直在线"吗?是,就别用 Serverless。
六、数据库连接:Serverless 的经典翻车点
这是几乎所有团队迁 Serverless 都会踩的坑,值得单独拎出来。
传统应用一个常驻进程持有一个连接池(20 条连接),复用一辈子。Serverless 不一样:每个函数实例是独立短命进程,并发一起来,云厂商瞬间开出几百个实例,每个都新建一条 DB 连接。PostgreSQL 这种进程模型的数据库,200 条连接就能把它内存吃光、max_connections 直接打爆。表现就是:FATAL: too many connections、连接超时、数据库 OOM。
解决方案有两条路:
方案 A:在 DB 前面加连接池中间件(PgBouncer)
[ Lambda ×N ] ──> [ PgBouncer (transaction mode) ] ──> [ PostgreSQL ]
复用少量连接,抗住瞬时并发
方案 B:用原生 Serverless 数据库
[ Function ] ──> [ Neon / PlanetScale / Aurora Serverless ]
HTTP API 或连接池内置,按存储和计算计费
- 方案 A:自建 PG 前面挂 PgBouncer,开
transaction pooling模式,把几百条短连接复用成十几条到 DB 的长连接。注意 transaction 模式下不能用 prepared statements、session-level advisory lock,Prisma 要开?pgbouncer=true。 - 方案 B:直接用 Neon、PlanetScale、Aurora Serverless v2 这类为 Serverless 设计的数据库——它们要么提供 HTTP 接口(连接即 HTTP 请求),要么内置池化,还能"缩到零"省钱。新项目这条路最省心。
一句话:Serverless + 传统直连 DB = 必炸。函数短命,就得给 DB 配池化,或干脆用 Serverless 原生 DB。
七、典型架构:函数 + 静态前端 + 托管 DB
把上面拼起来,这就是当下最主流的轻量现代栈:
┌──────────────────────────┐
用户 ──── CDN ──▶│ 静态前端 │
│ (Next.js SSG/SSR on Vercel)│
└─────────────┬────────────┘
│ API 调用(函数)
▼
┌──────────────────────────┐
│ Serverless Functions │ ◀── webhook / cron 触发
│ (认证、业务、文件处理) │
└───┬────────────┬──────────┘
│ │
┌─────────▼───┐ ┌─────▼────────┐
│ Serverless │ │ 对象存储 S3 │
│ DB (Neon) │ │ / R2 │
└─────────────┘ └──────────────┘
前端静态化上 CDN(Next.js 的 SSG/ISR 部署在 Vercel / Cloudflare Pages),业务逻辑编译成函数,数据放托管 DB,大文件放对象存储。全栈按用量计费、自动伸缩、缩到零。一个 MVP 用这套,从上线到月活破万,基础设施成本可能就没超过一杯咖啡。这套最适合独立开发者、创业团队、内部工具。
八、别 all-in:混合架构才是正解
最后一条,也是我见过最多团队栽跟头的地方:别 all-in Serverless。
Serverless 的甜区很明确,边界也很硬。一个像样的生产系统,通常是混合架构:核心交易、长连接、重计算用常驻服务(K8s / ECS / 裸机),边缘的、事件驱动的、突发的、低频的用 Serverless。比如电商:订单核心服务常驻,保证 P99 低延迟和长连接;图片缩略、对账邮件、定时报表、秒杀限流这些用函数;前端静态化上 CDN。各司其职,不要用一把锤子敲所有钉子。
判断一个组件该用哪种,问三个问题:它需要一直在线吗?(要→常驻)它的流量是突发的吗?(是→Serverless)它的延迟要求严苛吗?(严→常驻)。三个问题答完,选型基本就定了。
小结
- Serverless = FaaS(跑代码)+ BaaS(扛状态/存储),核心变化是按"执行"付费而非按"机器"付费。没流量不花钱、自动伸缩到零,是它对低频和事件驱动场景的杀手锏。
- 五条硬约束必须先认账:冷启动、执行时长限制、无状态、供应商锁定、调试难。优势不是免费的,它是用这几条约束换来的。
- 甜区是事件驱动(webhook/cron/文件处理)、突发流量、低频低流量、API 后端;雷区是长连接、常驻服务、严苛低延迟、重计算——"必须一直在线"的就别用。
- DB 连接是经典翻车点:函数短命会瞬间打爆直连 DB。要么前面挂 PgBouncer 做 transaction 池化,要么换 Neon / PlanetScale 这类 Serverless 原生 DB。
- 典型轻量栈:静态前端(CDN)+ Serverless 函数 + 托管 DB + 对象存储,但生产系统应该是混合架构——核心常驻、边缘 Serverless,各司其职。
一句话收尾:Serverless 不是把服务器藏起来,是把"什么时候该操心服务器"这件事交给了你——选对场景它便宜到离谱,选错场景它贵到离谱还慢。
Related
相关推荐
文章
Docker 部署 Next.js 社区项目的注意事项
围绕 DevOps、Next.js 的技术趋势、工程实践和独立开发视角。
文章
OpenTelemetry 如何帮助你观察 AI 应用?
围绕 DevOps、AI 的技术趋势、工程实践和独立开发视角。
文章
长运行工具调用:Operation、Poll 与 Cancel 的终态协议
初始请求超时后,工具可能仍在服务端运行;发出取消也不等于副作用已停止。本文为单次长运行工具调用建立 operation 身份、轮询水位、取消竞态和唯一终态接受点。
文章
Agent 记忆删除传播:从用户遗忘请求到可验证清除
删除主表一行不会清掉向量、摘要、缓存和恢复后的备份。本文用删除状态机、代际墓碑、派生血缘与端到端 canary 验证真正遗忘。