
作者:Echo_Wish
很多开发同学第一次接触 Serverless 的时候,第一反应都是:
“终于不用管服务器了!”
不用买机器,不用配置环境,不用扩容,不用半夜起来处理 CPU 飙升。
听起来是不是很美?
但是,当系统真正上线之后,很多运维同学会发现一个现实问题:
服务器没了,问题并没有消失,只是换了一种形式出现。
以前传统架构的问题是:
而 Serverless 时代的问题变成:
这就是 Serverless 可观测性的核心挑战。
今天我们聊三个最典型的问题:
冷启动、短生命周期、采样策略。
传统服务是什么样?
比如一个 Spring Boot 应用:
服务器启动
|
加载 JVM
|
加载 Spring
|
创建 Bean
|
监听端口
|
等待请求启动一次,运行几个月。
所以运维很好监控:
服务器状态
|
CPU
|
内存
|
网络
|
应用日志但是 Serverless 不一样。
比如 AWS Lambda、阿里云函数计算、Azure Functions:
请求来了:
用户请求
|
平台创建运行环境
|
下载代码
|
初始化依赖
|
执行函数
|
返回结果请求少的时候:
环境销毁下一次请求:
重新创建这就是大家经常说的:
冷启动(Cold Start)
假设我们有一个 Python Serverless 函数:
import time
def handler(event, context):
start = time.time()
result = do_business()
cost = time.time() - start
print({
"cost": cost
})
return result
def do_business():
time.sleep(0.5)
return "success"第一次调用:
函数初始化:
2秒
业务执行:
0.5秒
总耗时:
2.5秒第二次调用:
初始化:
0秒
业务执行:
0.5秒
总耗时:
0.5秒业务代码完全一样。
但是用户体验差了5倍。
问题来了:
如果我们只看业务耗时:
业务耗时 500ms监控显示:
“系统很健康。”
但是用户:
“为什么第一次打开这么慢?”
这就是 Serverless 监控的第一个坑。
很多企业刚开始做 Serverless,会直接套传统监控方案。
例如:
监控:
服务器CPU
服务器内存
服务器磁盘结果发现:
全部正常。
但是业务投诉:
“接口偶尔超时。”
为什么?
因为 Serverless 没有长期运行的服务器。
你的监控对象变成了:
服务器
↓
函数实例
↓
一次请求监控粒度越来越细。
以前:
一天一个服务指标现在:
一次请求一个生命周期一个完整链路应该是:
请求进入
↓
触发函数
↓
初始化环境
↓
加载依赖
↓
执行代码
↓
调用数据库
↓
调用第三方服务
↓
返回结果所以我们需要记录:
指标 | 作用 |
|---|---|
Cold Start次数 | 判断冷启动影响 |
初始化时间 | 定位启动慢 |
函数执行时间 | 业务性能 |
错误率 | 稳定性 |
调用链 | 定位上下游问题 |
资源消耗 | 成本优化 |
很多团队监控喜欢看平均响应时间:
例如:
接口平均耗时:
300ms看起来很好。
但是 Serverless 最大的问题:
平均值会骗人。
比如:
1000次请求:
990次:
100ms
10次:
5000ms平均:
149ms非常漂亮。
但是那10个用户:
已经骂娘了。
所以 Serverless 必须关注:
例如:
P50:
100ms
P95:
800ms
P99:
5000ms说明:
大部分正常。
但是极端情况严重。
代码里面也应该增加冷启动标记:
import time
is_cold_start = True
def handler(event, context):
global is_cold_start
start = time.time()
if is_cold_start:
print({
"cold_start": True
})
is_cold_start = False
result = process(event)
print({
"duration":
time.time()-start
})
return result这样日志里面:
{
cold_start:true,
duration:2.8
}你马上知道:
这次慢,是因为冷启动。
这是 Serverless 第二个坑。
传统应用:
服务运行一年
日志保存一年但是 Serverless:
请求来了
执行3秒
结束
销毁生命周期可能只有几百毫秒。
如果日志同步上传:
可能:
函数结束
↓
日志还没发送
↓
数据丢失所以 Serverless 日志设计必须:
例如:
错误日志:
import json
import traceback
def handler(event, context):
try:
do_work()
except Exception:
log = {
"error":
traceback.format_exc()
}
send_async(log)
raise不要:
业务代码
↓
等待日志系统返回
↓
结束否则:
日志影响业务。
很多大厂现在采用:
函数
↓
本地缓冲
↓
消息队列
↓
日志平台例如:
Lambda
↓
Kafka
↓
ElasticSearch
↓
Kibana或者:
函数
↓
OpenTelemetry Collector
↓
Trace系统Serverless 最大特点:
调用量巨大。
假设:
每天:
10亿请求。
如果每一次:
完整Trace:
请求参数
↓
函数
↓
数据库
↓
Redis
↓
第三方API全部保存。
成本直接爆炸。
所以必须采样。
最简单:
固定采样。
例如:
只记录10%。
代码:
import random
def should_sample():
return random.random() < 0.1
if should_sample():
collect_trace()效果:
100万个请求
↓
保存10万个成本下降90%。
但是问题来了:
如果错误只出现0.01%。
可能:
一次都采不到。
怎么办?
答案:
规则:
正常请求:
采1%慢请求:
100%采集错误请求:
100%采集例如:
def sample_request(response):
if response.status >= 500:
return True
if response.time > 3000:
return True
return random.random()<0.01这才符合实际运维需求。
现在越来越多团队使用:
OpenTelemetry
原因很简单:
以前:
应用
|
监控平台A换平台:
重新改代码很痛苦。
现在:
应用
↓
OpenTelemetry
↓
任意监控平台比如:
Prometheus
Jaeger
Grafana
Elastic都可以接。
简单示例:
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
def handler(event, context):
with tracer.start_as_current_span(
"serverless-request"
):
result = business()
return result自动生成:
TraceID:
abc123
Span:
serverless-request
Duration:
300ms排查问题效率提升非常明显。
以前运维关注:
机器
↓
服务
↓
进程Serverless之后:
关注:
请求
↓
函数
↓
调用链
↓
业务结果运维从:
“服务器管理员”
变成:
“系统可观测性工程师”。
我的理解:
Serverless 最大价值不是“不需要运维”。
而是:
把低价值的服务器维护交给平台,把运维精力释放出来,投入到系统稳定性和业务体验上。
但是前提是:
你必须建立新的可观测体系。
否则:
服务器没了,
黑盒来了。
Serverless 让开发效率提升了一大截。
但是它也给运维提出了新的挑战:
未来的 Serverless 运维,不再是谁会重启服务器。
而是谁能够回答:
“刚才那个用户为什么慢?”
“这个错误为什么只发生千分之一?”
“一次请求到底经过了哪里?”
这才是真正属于 Serverless 时代的可观测性能力。
服务器可以消失,但系统的问题永远存在。
区别只是:
以前我们盯机器,
现在我们盯每一次请求。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。