3、Serverless 应用场景剖析:Web 后端、数据处理、定时任务、消息处理、IoT 后端等典型场景
说实话,很多朋友问我:“Serverless 到底能干啥?是不是只能跑个 Hello World?”
嗯,这个问题我太有感触了。我刚接触 Serverless 那会儿,也觉得它就是个“玩具”。直到我在一个电商项目中,用 Serverless 扛住了双十一的流量洪峰,才彻底改观。
今天,我就带你看看 Serverless 真正发力的几个典型场景。每个场景我都会结合自己的实战经验来讲,希望能帮你少走弯路。
3.1 Web 后端:从“搬砖”到“搭积木”
Web 后端是 Serverless 最成熟的应用场景之一。说白了,就是把传统的 Web 服务器拆成一个个函数。
我个人习惯把这类应用分为两种:
- 轻量级 API 网关:比如用户注册、登录、获取商品列表。这些接口逻辑简单,但调用频率高。
- BFF(Backend For Frontend):专门为前端定制的聚合层。把多个微服务的数据拼装一下,返回给前端。
举个例子,我之前帮一家创业公司做用户中心。他们原来的架构是 Spring Boot 单体应用,每次上线都要重启整个服务。后来我帮他们改造成了 Serverless:
// 一个典型的用户注册函数(Node.js)
exports.handler = async (event) => {
const { username, password } = JSON.parse(event.body);
// 参数校验
if (!username || !password) {
return { statusCode: 400, body: '参数不完整' };
}
// 调用数据库 SDK
const user = await db.insert({ username, password });
return {
statusCode: 200,
body: JSON.stringify({ userId: user.id })
};
};
你想想看,这样做的好处是什么?
- 每个接口独立部署,互不影响
- 自动扩缩容,流量再大也不怕
- 按实际调用次数付费,没流量就不花钱
3.2 数据处理:让“脏活累活”自动化
数据处理是 Serverless 的另一个“舒适区”。尤其是那些需要定时跑、或者事件触发的批处理任务。
我记得有一次,客户需要每天凌晨 2 点处理前一天的用户行为日志。数据量大概 500GB,需要做清洗、去重、然后导入数据仓库。
传统做法是:租一台高配服务器,装个 Cron 任务,跑完关机。但问题是,这台机器大部分时间都在空转,浪费钱。
用 Serverless 怎么做?
- 用户上传日志到 OSS(对象存储)
- OSS 的 Put 事件自动触发函数
- 函数读取日志,做 ETL 处理
- 结果写入数据仓库
这里有个关键点:数据分片。如果单个文件太大(比如超过 1GB),函数可能会超时。我的做法是:
// 数据分片处理示例
exports.handler = async (event) => {
const { bucket, key } = event;
const fileSize = await getFileSize(bucket, key);
// 如果文件超过 100MB,拆分成多个子任务
if (fileSize > 100 * 1024 * 1024) {
const chunks = splitFile(bucket, key, 100 * 1024 * 1024);
// 异步调用多个函数并行处理
await Promise.all(chunks.map(chunk => invokeFunction(chunk)));
} else {
// 直接处理
await processFile(bucket, key);
}
};
3.3 定时任务:告别“Cron 噩梦”
定时任务,说白了就是“闹钟”。到了指定时间,自动执行一段代码。
传统做法是在服务器上写 Cron 表达式。但问题来了:
- 服务器挂了怎么办?
- 任务执行时间重叠了怎么办?
- 怎么监控任务是否成功?
Serverless 的定时触发器完美解决了这些问题。我常用的场景包括:
| 场景 | 触发频率 | 说明 |
|---|---|---|
| 数据备份 | 每天凌晨 3 点 | 把数据库快照备份到对象存储 |
| 报表生成 | 每天早上 8 点 | 生成前一天的运营报表,发送邮件 |
| 缓存预热 | 每 10 分钟 | 把热点数据提前加载到 Redis |
| 健康检查 | 每 5 分钟 | 检查各个服务是否正常运行 |
嗯,这里要注意一个细节:幂等性。定时任务可能会因为网络抖动被重复执行。我习惯在函数开头加一个“去重检查”:
// 幂等性检查示例
exports.handler = async (event) => {
const taskId = event.time; // 用时间戳作为任务 ID
// 检查这个任务是否已经执行过
const executed = await redis.get(`task:${taskId}`);
if (executed) {
console.log('任务已执行,跳过');
return;
}
// 执行实际逻辑
await doBackup();
// 标记任务已完成
await redis.set(`task:${taskId}`, 'done', 'EX', 86400);
};
3.4 消息处理:异步解耦的“利器”
消息处理,说白了就是“生产者-消费者”模式。生产者发消息,消费者处理消息。
我参与过一个订单系统,用户下单后需要做一系列操作:扣库存、发短信、更新积分、通知物流。如果这些都在一个请求里完成,接口响应时间会很长。
用 Serverless 怎么解?
- 用户下单后,把订单信息发送到消息队列
- 消息队列触发多个函数并行处理
- 每个函数只负责一件事
这样做的好处很明显:
- 主流程(下单)响应快,用户体验好
- 各个任务独立,一个失败不影响其他
- 可以根据消息积压情况自动扩缩容
3.5 IoT 后端:海量设备的“守门人”
IoT 场景对 Serverless 来说,简直是“天作之合”。
你想想看,一个 IoT 平台可能有几十万台设备。每台设备每隔几秒就上报一次数据。如果用传统服务器,你得准备多少台机器才能扛住这种流量?
而且,设备上报的数据往往是“突发性”的。比如智能电表,每天 0 点会集中上报前一天的数据。这时候流量可能是平时的 100 倍。
Serverless 的自动扩缩容能力,正好解决了这个问题。我做过一个智能路灯项目,架构是这样的:
- 设备通过 MQTT 协议上报数据
- IoT 网关接收数据,转发到函数
- 函数做数据清洗、格式转换
- 清洗后的数据写入时序数据库
- 如果数据异常(比如电压过高),触发告警函数
这里有个坑,我踩过:设备认证。千万不能让非法设备接入你的平台。我建议使用设备证书或 Token 认证,而不是简单的设备 ID 校验。
// 设备数据上报处理示例
exports.handler = async (event) => {
const { deviceId, timestamp, data } = event;
// 1. 设备认证(检查设备是否在白名单中)
const isValid = await checkDeviceAuth(deviceId);
if (!isValid) {
console.error(`非法设备: ${deviceId}`);
return { statusCode: 403 };
}
// 2. 数据校验(检查数据格式是否正确)
if (!validateData(data)) {
console.error(`数据格式错误: ${deviceId}`);
return { statusCode: 400 };
}
// 3. 数据清洗(去除异常值)
const cleanData = cleanData(data);
// 4. 写入时序数据库
await writeToTSDB(deviceId, timestamp, cleanData);
// 5. 检查是否需要告警
if (isAbnormal(cleanData)) {
await sendAlert(deviceId, cleanData);
}
return { statusCode: 200 };
};
3.6 场景选择:一张表说清楚
最后,我整理了一张表,帮你快速判断某个场景是否适合 Serverless:
| 场景 | 适合程度 | 关键考量 |
|---|---|---|
| Web 后端(轻量 API) | ★★★★★ | 冷启动延迟、函数超时限制 |
| 数据处理(ETL) | ★★★★★ | 数据分片、执行时间 |
| 定时任务 | ★★★★☆ | 幂等性、任务依赖 |
| 消息处理 | ★★★★★ | 重试策略、死信队列 |
| IoT 后端 | ★★★★☆ | 设备认证、数据清洗 |
| 长时间运行任务 | ★★☆☆☆ | 函数超时限制(通常 15 分钟) |
| 有状态应用 | ★★☆☆☆ | 需要额外引入外部存储 |
说白了,Serverless 不是万能的。但它确实能解决很多传统架构的痛点。关键是要选对场景,用对方法。
下一章,我会带你深入 Serverless 的“冷启动”问题,聊聊怎么把启动时间从 5 秒降到 100 毫秒。到时候见。