FaaS真香到肉疼:什么时候该从Serverless退回K8s?
我是 Echo_Wish。
这几年做云原生,Serverless/FaaS 基本绕不开。
刚开始接触的时候,很多人的第一反应都是:
“不用买服务器、不用管机器、按调用次数付费,这不就是白嫖吗?”
确实香。
以前部署一个接口,得准备服务器、装环境、配 Nginx、搞进程守护、配监控,还得考虑扩容。
现在呢?
用户请求
↓
API Gateway
↓
FaaS
↓
执行代码
↓
返回结果
业务量小的时候,Serverless 甚至可以做到一个月几块钱。
但问题也恰恰出在这里。
Serverless 最容易让人产生一种错觉:用得越多,成本越低。
实际上,很多系统上线半年以后,账单开始变得有点“扎心”。
尤其是那些高频、稳定、长时间运行的业务,你会慢慢发现:
Serverless 并不是服务器消失了,而是服务器成本换了一种方式向你收费。
所以今天我们聊一个很现实的问题:
什么时候应该从 Serverless/FaaS 回退到 K8s?
一、Serverless 最大的坑:低成本不等于低总成本
先看一个非常简单的场景。
假设我们有一个订单查询接口:
def get_order(order_id):
order = query_database(order_id)
return {
"order_id": order_id,
"status": order.status
}
业务刚上线的时候,每天只有几千次请求。
这个时候用 FaaS 非常舒服。
因为你根本不用关心:
- 服务器买多少;
- CPU 配多少;
- 内存配多少;
- 怎么扩容;
- 机器闲着怎么办。
请求来了就执行,请求没了就不计费。
这时候 Serverless 是非常划算的。
但是业务增长以后,情况发生变化。
假设:
每天请求:1000万
平均QPS:115
高峰QPS:500
这个时候问题来了。
你会发现这个函数已经不是“偶尔执行”。
而是:
一直有人叫它干活。
这时候 FaaS 的按量计费模型,反而可能成为成本压力。
二、真正决定成本的,不是QPS,而是“持续使用率”
很多人在比较 Serverless 和 K8s 的时候,喜欢直接问:
“哪个便宜?”
这个问题其实不够准确。
更应该问:
我的计算资源到底是“偶尔用”,还是“长期用”?
这是两种完全不同的业务模型。
例如:
场景A:偶发任务
09:00 10次
10:00 2次
11:00 0次
12:00 100次
13:00 3次
14:00 0次
这种业务非常适合 FaaS。
因为你根本没必要为了这几个请求一直养着服务器。
场景B:持续高频接口
00:00 ███████
06:00 ████████
09:00 ██████████
12:00 █████████
18:00 ██████████
22:00 ████████
这种业务就不一样了。
机器基本一直在工作。
这时候:
FaaS:
调用越多 → 费用越高
K8s:
节点成本相对固定
于是一个非常有意思的现象出现了:
Serverless 业务越成功,成本反而越容易失控。
这就是我认为 FaaS 最大的成本陷阱。
三、第一个信号:账单开始跟业务量“线性增长”
假设你的函数:
单次执行:
CPU:1 vCPU
内存:512MB
平均执行时间:200ms
一个月调用:
1亿次
你可能觉得:
“一次才200ms,能贵到哪里去?”
问题就在“一亿次”。
单次看起来很便宜。
乘以一亿以后,就完全不是一个概念了。
而且 FaaS 的成本通常不只有计算费用。
还可能包括:
函数计算
+
API Gateway
+
网络流量
+
日志
+
监控
+
消息队列
+
数据库访问
+
公网流量
最后账单可能长这样:
FaaS计算: ¥8,000
Gateway: ¥2,000
日志: ¥3,500
网络: ¥4,000
其他: ¥2,500
----------------
合计: ¥20,000
然后运维同学突然发现:
“我是不是把服务器卖了,然后换成了一张更贵的账单?”
😂
四、第二个信号:你的函数已经开始“常驻”
FaaS 最适合的是什么?
一句话:
短、快、无状态。
例如:
def resize_image(image):
image = download(image)
image = resize(image)
upload(image)
执行:
下载
↓
处理
↓
上传
↓
结束
非常漂亮。
但是如果你开始写这种代码:
while True:
message = consume_message()
if message:
process(message)
我建议你停下来想一下。
因为你实际上已经开始把 FaaS 当服务器用了。
这种程序本质上是:
“我要一个进程一直活着。”
那为什么不直接上 Kubernetes?
K8s 部署一个 Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-worker
spec:
replicas: 3
template:
spec:
containers:
- name: worker
image: order-worker:v1.0
让它老老实实跑在那里。
反而更加符合这个业务的模型。
五、第三个信号:冷启动已经开始影响用户体验
Serverless 一个绕不开的问题:
冷启动。
假设一个函数平时没有请求。
突然来了一个:
Request
↓
创建运行环境
↓
加载Runtime
↓
加载依赖
↓
初始化SDK
↓
连接数据库
↓
执行代码
最后用户:
“怎么点一下按钮转半天?”
尤其是 Python、Java、Node.js 这种依赖比较多的应用,如果初始化阶段很重,冷启动就更加明显。
例如:
import tensorflow
import pandas
import sklearn
import torch
然后:
def handler(event):
return predict(event)
函数本身可能只执行100ms。
但是:
环境启动:1.5s
加载依赖:2s
初始化模型:3s
真正执行:0.1s
最后:
用户等待:6.6s
这时候你就会发现:
你省下来的服务器成本,可能换成了用户体验成本。
如果这是一个后台批处理任务,没关系。
如果这是:
支付
下单
登录
查询
实时推荐
实时风控
那就另说了。
六、第四个信号:你开始疯狂给 FaaS 加“外挂”
这个是我特别想提醒大家的。
最开始:
API Gateway
↓
FaaS
后来慢慢变成:
API Gateway
↓
FaaS
↓
Redis
↓
MySQL
↓
MQ
↓
OSS
↓
另一个FaaS
↓
第三个FaaS
然后为了稳定:
FaaS
+
Redis
+
MQ
+
Service Mesh
+
Tracing
+
APM
+
日志系统
+
各种连接池
最后你会发现:
函数没多少钱,周围的东西越来越贵。
这就是 Serverless 另一个很隐蔽的成本:
架构复杂度成本。
很多团队为了保持“Serverless”,不断往旁边加基础设施。
结果系统越来越复杂。
这时候我反而建议:
别为了 Serverless 而 Serverless。
技术架构是服务业务的。
不是拿来完成 KPI 的。
七、那什么时候应该考虑 K8s?
我个人一般会看下面几个指标。
① 业务流量长期稳定
例如:
全天QPS:
100
120
110
130
115
125
没有明显的波峰波谷。
这种业务非常适合容器化。
因为资源利用率比较稳定。
K8s 可以直接把资源跑起来:
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
然后通过 HPA:
低峰:
3 Pod
高峰:
10 Pod
流量下降:
自动缩回3 Pod
你仍然拥有弹性。
但成本模型更加可控。
八、② 单个服务调用量巨大
比如:
每天:
10亿次调用
这种情况下,就应该认真算一笔账。
不要只看:
“FaaS单次调用很便宜。”
而是要算:
月度FaaS成本
VS
K8s节点成本
例如:
FaaS:
¥50,000/月
K8s:
8台计算节点
¥25,000/月
这时候继续坚持 FaaS 就没有太大意义。
当然,真实成本一定要根据具体云厂商、实例规格、流量、执行时间等重新计算。
不要拿网上的价格表直接拍脑袋做架构决策。
九、③ 服务需要长期运行
如果你的程序天然就是:
WebSocket
长连接
消息消费者
实时推送
任务Worker
持续计算
那 K8s 通常更自然。
比如:
while True:
task = queue.get()
process(task)
这种程序本质上就是一个 Worker。
你可以:
Deployment
+
HPA
+
Kafka
+
Redis
组成稳定的计算平台。
没必要强行把它拆成:
消息来了
↓
触发FaaS
↓
启动环境
↓
处理
↓
退出
架构不是越“Serverless”越先进。
合适才是最重要的。
十、④ 你已经开始严重依赖 FaaS 厂商特性
这是一个非常容易被忽略的问题。
例如代码里面到处都是:
import cloud_provider_sdk
或者:
context.function_name
context.request_id
context.runtime
然后业务代码大量依赖:
厂商事件模型
厂商触发器
厂商权限体系
厂商日志
厂商网络
这时候迁移成本就开始增加。
今天:
AWS Lambda
明天:
Azure Functions
后天:
阿里云函数计算
你会发现:
“理论上可以迁移,实际上不太想迁。”
这就是典型的 Vendor Lock-in。
而容器相对来说更加标准化。
例如:
FROM python:3.12
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]
然后:
Docker
↓
K8s
↓
任意云环境
迁移的自由度通常会更高。
十一、千万不要理解成“Serverless不好”
这里我要特别强调一下。
我不是反对 Serverless。
恰恰相反,我认为 Serverless 是非常优秀的技术。
只是:
没有免费的午餐。
Serverless 真正适合的业务通常是:
流量波动大
+
请求短
+
无状态
+
执行时间短
+
业务迭代快
+
团队运维能力有限
比如:
图片处理
文件转换
定时任务
Webhook
API后端
事件处理
数据清洗
偶发计算
这些场景我甚至会优先考虑 FaaS。
因为它能让开发团队:
少管机器,多管业务。
这才是 Serverless 最大的价值。
十二、我更推荐的,其实是“混合架构”
很多人喜欢问:
“到底选 Serverless 还是 K8s?”
我的答案是:
为什么一定要二选一?
完全可以:
┌── FaaS
│
用户 → Gateway ─────┼── K8s
│
└── MQ → FaaS
例如:
核心交易服务
放 K8s:
订单
支付
库存
用户
因为:
稳定
高频
长期运行
异步任务
放 FaaS:
图片压缩
邮件发送
数据转换
Webhook
日志处理
因为:
偶发
短生命周期
事件驱动
于是整个系统形成:
┌─────────────┐
│ K8s │
│ 核心业务服务 │
└──────┬──────┘
│
MQ
│
┌──────▼──────┐
│ FaaS │
│ 异步事件处理 │
└─────────────┘
这种架构在我看来,比“全家桶 Serverless”更加务实。
十三、最后给大家一个简单的判断公式
如果你不知道到底应该选哪个,可以先问自己5个问题:
① 请求是不是长期稳定?
② 函数是不是经常运行?
③ 是否存在大量长连接?
④ 是否对冷启动非常敏感?
⑤ FaaS外围基础设施是不是越来越复杂?
如果大部分答案都是:
YES
那就别硬撑了。
认真看看 K8s。
反过来,如果你的业务是:
流量忽高忽低
+
任务短
+
调用不频繁
+
事件驱动
+
不想维护服务器
那 Serverless 依然非常香。
写在最后
我一直觉得,技术选型最怕的一句话就是:
“别人都这么用。”
前几年大家说:
“微服务才是未来。”
后来又说:
“Serverless才是未来。”
再后来:
“AI Agent才是未来。”
但对于真正负责生产环境的人来说,哪有什么“唯一正确答案”。
架构从来不是信仰,而是一笔账。
Serverless 解决的是:
“我不想管服务器。”
K8s 解决的是:
“我需要对计算资源拥有更强的控制权。”
当业务量很小时,Serverless 是朋友。
当业务量巨大且稳定时,Serverless 可能变成财务部门的朋友。
而当你的 FaaS 开始出现:
高频调用
+
长期运行
+
冷启动敏感
+
复杂外挂
+
账单持续上涨
这时候就该认真考虑:
是不是到了从 Serverless 回到 K8s 的时候?
最后送大家一句我自己比较认同的话:
不要因为 Serverless 先进,就让所有业务都 Serverless;也不要因为 K8s 可控,就把所有东西都塞进 K8s。
真正成熟的架构师,不是“选对技术”的人。
而是知道:
什么时候该用它,以及什么时候该放弃它。
这可能才是云原生时代,运维人员最重要的一种能力。