FaaS 详解
你正在开发一个图片处理服务。传统做法是:买一台服务器,部署一个 Tomcat 应用,配置一个 4 核 8G 的实例,然后祈祷大促时它能扛住。结果呢?平时 CPU 利用率 5%,大促时流量是平时的 50 倍,服务器直接挂掉。
FaaS(Function as a Service)换了一种思路:不要买服务器了,你的代码就是服务。云负责在任何时候运行你的代码——不管是一天一次还是每秒一万次,你只需要为实际执行时间付费。
FaaS 核心概念
FaaS 是 Serverless 架构的核心支柱。它将应用逻辑分解为独立的函数,每个函数响应特定的事件,执行完成后释放所有资源。
核心特征
- 无服务器管理:开发者不需要关心服务器操作系统、运行时配置、安全补丁
- 事件驱动:函数由特定事件触发,而不是持续监听请求
- 自动扩缩容:平台根据请求量自动启动或销毁函数实例
- 按执行计费:只对实际执行时间收费,空闲时不产生费用
与传统函数的区别
FaaS 函数与传统编程中的「函数」概念不同:
触发器类型
触发器是 FaaS 的核心概念——没有触发器,函数永远不会执行。每个云厂商都提供了丰富的触发器类型:
HTTP 触发器
最常见的触发器类型,用于构建 Web API。
HTTP 触发器通常配合 API 网关使用,支持请求路由、认证限流等功能。
队列/消息触发器
当消息队列中有新消息时触发函数,常用于异步处理任务。
批量处理优化:大多数消息触发器支持批量消费,将多条消息打包一次发给函数,减少函数调用次数和网络开销。
定时触发器
类似 cron 表达式,定时执行函数。适合定时任务、报表生成、数据同步等场景。
对象存储触发器
当对象存储(如 S3、OSS)中上传或删除文件时触发函数。典型场景:图片压缩、音视频转码、日志分析。
触发器组合
一个函数可以绑定多个触发器,实现复杂的业务流程:
函数生命周期
函数从创建到销毁,经历以下阶段:
部署阶段
- 开发者打包函数代码和依赖
- 上传到云平台
- 平台解压并缓存代码包
- 函数进入「就绪」状态
调用阶段
当事件到达时,平台按以下流程处理:
销毁阶段
函数执行完成后,实例的处理:
- 保持热备:平台通常会保留最近使用的实例一段时间(通常 5-15 分钟),等待下一个请求
- 完全销毁:长时间无请求后,平台销毁实例,释放资源
执行环境
运行时支持
主流云厂商支持的运行时:
自定义运行时
如果官方运行时不满足需求,可以使用自定义运行时:
冷启动与热复用
冷启动
当没有可用实例时,平台需要创建新实例,这个过程称为冷启动。冷启动包括:
- 分配容器资源:从资源池中申请一个容器
- 启动运行时:初始化语言运行时(如 JVM)
- 加载函数代码:解压和加载函数包
- 执行初始化逻辑:运行函数外的静态代码块
热复用
为减少冷启动延迟,平台会保持活跃实例的温池:
热复用的不确定性:平台可以随时销毁空闲实例,不保证任何实例的持久性。函数代码必须是无状态的,或者状态必须存储在外部服务中。
资源限制
FaaS 平台对函数配置有明确的限制:
内存配置
内存配置直接影响执行性能和冷启动速度。内存越大,CPU 配额通常也越大。
执行时长限制
并发限制
适用与不适用场景
FaaS 适合的场景
- 事件驱动处理:S3 上传处理、消息队列消费、定时任务
- Webhook 处理:接收第三方回调
- 实时数据处理:流式数据转换和分析
- 轻量级 API:业务逻辑简单的微服务
- 突发流量处理:大促、投票、直播
FaaS 不适合的场景
- 长时间计算:机器学习训练、科学计算
- 需要长连接:WebSocket、实时通信
- 资源密集型:需要 GPU、更多内存
- 状态复杂:频繁的状态读写,且无法外部化
延伸思考
FaaS 的函数粒度设计是架构决策的关键。粒度太粗,失去弹性优势;粒度太细,增加调用延迟和协调复杂度。
常见的函数拆分策略:
- 按业务能力拆分:用户函数、订单函数、支付函数
- 按处理阶段拆分:验证函数、转换函数、存储函数
- 按触发源拆分:HTTP 函数、队列函数、定时函数
如何判断拆分是否合理?一个函数应该是原子业务操作的最小单元——如果两个操作需要共同回滚,就应该合并为一个函数。