核心概念与术语:FaaS、BaaS、冷启动、无状态设计、事件驱动、按需付费模型

好,咱们正式开始聊 Serverless 的核心概念。说实话,很多新手一上来就被这些术语搞懵了。什么 FaaS、BaaS,听着像绕口令。别急,我一个一个给你拆开讲。这些概念搞懂了,后面整个架构设计你就通了。

FaaS:函数即服务

FaaS 是 Serverless 的基石。说白了,就是把你的代码打包成一个函数,扔到云上跑。你不用管服务器,不用管操作系统,甚至不用管运行时环境。

我在项目中遇到过最典型的场景:用户上传图片后,自动生成缩略图。以前我得搭个图片处理服务,部署到服务器上,还得考虑并发。用 FaaS 呢?写个函数,绑定到对象存储的事件上,完事。

核心特征:

  • 代码以函数粒度部署
  • 由事件触发执行
  • 执行完即销毁
  • 按调用次数和时长计费
// 一个典型的 FaaS 函数(Node.js 示例)
exports.handler = async (event) => {
  // event 里包含了触发事件的所有信息
  const imageUrl = event.Records[0].s3.object.key;
  
  // 处理逻辑
  const thumbnail = await generateThumbnail(imageUrl);
  
  return {
    statusCode: 200,
    body: JSON.stringify({ thumbnailUrl: thumbnail })
  };
};

你想想看,这种模式最大的好处是什么?弹性伸缩。来了 100 个请求,自动拉起 100 个实例。没人访问时,一个实例都没有。零成本闲置。

BaaS:后端即服务

BaaS 是 FaaS 的好搭档。它提供了一堆现成的后端能力:数据库、认证、存储、消息队列等等。你不需要自己搭建这些基础设施。

我个人习惯把 BaaS 理解为「乐高积木」。你需要用户登录?直接调认证 API。需要存数据?调数据库 API。需要发消息?调消息队列 API。

我的经验: 刚开始用 BaaS 时,我总担心被厂商锁定。后来想通了——业务跑起来比什么都重要。真有迁移需求时,加个适配层就行了。

BaaS 服务 典型产品 解决的问题
用户认证 Auth0, AWS Cognito 注册、登录、权限管理
数据库 Firebase, DynamoDB 数据存储与查询
对象存储 S3, OSS 文件上传、下载、CDN
消息队列 SQS, Pub/Sub 异步通信、削峰填谷

冷启动:躲不开的坑

冷启动是 Serverless 最让人头疼的问题。为什么会这样?因为函数实例不是一直活着的。当请求来了,平台得先拉起一个容器,加载你的代码,初始化运行时环境,然后才能执行。

我曾经踩过一个坑:一个金融交易系统的风控函数,冷启动耗时 3 秒。用户等不了啊。后来怎么解决的?用了预留并发 + 定时预热。

避坑指南: 我曾经天真地以为所有函数都能接受冷启动。直到线上出了事故才明白——对延迟敏感的业务,必须做预热策略。比如支付回调、实时推荐这些场景,冷启动就是灾难。

冷启动的典型耗时分布:

  • 容器启动:100-300ms
  • 运行时初始化:200-500ms
  • 代码加载:100-200ms
  • 业务初始化:取决于你的代码

嗯,这里要注意:Java 和 .NET 的冷启动比 Node.js、Python 慢得多。选语言时得权衡一下。

无状态设计:Serverless 的命根子

无状态设计,说白了就是函数不保存任何本地状态。每次调用都是全新的环境。你上次写入的临时文件,这次调用时已经没了。

我刚开始做 Serverless 时犯过一个低级错误:把用户会话信息存在函数的内存里。结果用户第二次请求时,被路由到了另一个实例,会话丢了。用户直接掉线。

正确的做法:

  • 状态存到外部存储(Redis、数据库)
  • 文件存到对象存储(S3、OSS)
  • 会话信息用 JWT 或分布式缓存
  • 日志直接打到集中式日志系统
// ❌ 错误示范:依赖本地状态
let userSession = {};

exports.handler = async (event) => {
  userSession[event.userId] = event.data;
  // 下次调用时,userSession 可能已经没了
};

// ✅ 正确示范:使用外部存储
const redis = require('redis');
const client = redis.createClient();

exports.handler = async (event) => {
  await client.set(event.userId, JSON.stringify(event.data));
  // 状态持久化,任何实例都能访问
};

事件驱动:一切皆事件

Serverless 是事件驱动的。什么意思?函数不是主动运行的,而是被事件触发的。文件上传了、数据库变了、消息队列来了新消息——这些都是事件。

你想想看,这种模式天然适合异步处理。用户下单 -> 触发订单处理函数 -> 触发库存更新函数 -> 触发通知函数。整个链路像流水线一样自动流转。

我的建议: 设计事件驱动架构时,一定要考虑事件幂等性。同一个事件被处理两次,结果应该一样。我在项目中就用过事件去重表,效果很好。

常见的事件源:

  • HTTP 请求(API Gateway)
  • 数据库变更(CDC)
  • 文件上传/删除
  • 定时任务(Cron)
  • 消息队列消息
  • IoT 设备数据

按需付费模型:省钱还是烧钱?

按需付费是 Serverless 最大的卖点。你只为实际使用的资源付费,不为闲置资源买单。听起来很美好,对吧?

但我要泼点冷水:这个模型不是所有场景都省钱。我见过一个团队,把高频调用的 API 也迁到了 Serverless,结果账单比原来还高。为什么?因为每次调用都要计费,高频场景下累积起来很可观。

避坑指南: 我曾经帮一个客户优化 Serverless 成本。发现他们有个函数每秒被调用 1000 次,每次执行 500ms。算下来一个月光这个函数就花了 2 万美金。后来改成常驻服务,成本降了 80%。

场景 Serverless 成本 传统服务器成本 推荐方案
低频调用(每天几百次) 极低 高(服务器闲置) Serverless
高频调用(每秒上千次) 低(资源复用) 传统服务
突发流量 按需付费 需预留资源 Serverless
稳定负载 偏高 最优 传统服务

说白了,按需付费模型最适合「间歇性、突发性、不可预测」的工作负载。如果你的流量像心跳一样规律,那传统服务器反而更划算。

好了,这六个核心概念讲完了。它们之间是相互关联的:FaaS 提供计算能力,BaaS 提供后端服务,冷启动是性能瓶颈,无状态设计是架构约束,事件驱动是触发机制,按需付费是经济模型。搞懂这些,你就掌握了 Serverless 的底层逻辑。