05 线上稳定性与可观测
学习目标:能设计可鉴权、可路由、可限流、可熔断、可 fallback、可灰度、可回滚、可弹性伸缩、可观测(含质量/成本)的模型服务入口;掌握 OpenTelemetry GenAI 语义约定的六层结构。 重点度:必会(20 分)
概述#
模型服务进入生产后,不能直接让业务访问裸实例——需要解决:
谁能调用?调用哪个模型?超量了怎么办?模型挂了怎么办?
延迟升高怎么办?负载有波峰波谷怎么扩缩?
输出质量变差怎么发现?每调用一次花了多少钱?核心问题:如何把模型服务变成可稳定接入、可观测、可控成本、可弹性伸缩的线上服务?
这一章的核心能力矩阵:AI Gateway → 稳定性 → 弹性伸缩 → 可观测。2026 年的新增重点是 OpenTelemetry GenAI 语义约定、scale-to-zero、效果可观测(质量/幻觉)。
AI Gateway:模型服务的统一入口#
为什么需要专门的 AI Gateway#
普通 API Gateway(Nginx/Kong/APISIX)懂的是 HTTP 路由、限流、鉴权,但它不懂 LLM——不知道什么是 token、什么是模型路由、什么是 prompt 成本。
AI Gateway 在普通网关的基础上,增加 LLM 专属能力:
普通 API Gateway AI Gateway(额外能力)
───────────────── ──────────────────────
路由 / 限流 / 鉴权 模型路由 / token 计费
负载均衡 / 重试 Virtual Key / 租户隔离
成本统计 / 模型 Fallback
Prompt 审计 / Guardrails
context window fallbackLiteLLM:开源 LLM 网关的事实标准#
核心定位:所有 LLM Provider 都翻译成 OpenAI 兼容接口,然后做网关该做的事。
两种模式:
- SDK 模式:Python 库,
from litellm import completion,适合本地脚本 - Proxy 模式:HTTP 服务,集中管控、配额、审计、Fallback,生产唯一选择
最小配置:
model_list:
- model_name: gpt-4o-mini # 业务侧看到的模型名(alias)
litellm_params:
model: openai/gpt-4o-mini # 实际后端
api_key: os.environ/OPENAI_API_KEY
- model_name: llama-70b-internal
litellm_params:
model: openai/default
api_base: http://vllm-llama70b:8000/v1
api_key: EMPTY
- model_name: deepseek-v3
litellm_params:
model: openai/default
api_base: http://sglang-deepseek:30000/v1
api_key: EMPTY
router_settings:
routing_strategy: usage-based-routing-v2
fallbacks:
- gpt-4o-mini: ["claude-sonnet", "qwen-max"]
context_window_fallbacks:
- gpt-4o-mini: ["claude-sonnet"] # prompt 超长时自动切大上下文模型
general_settings:
master_key: sk-master-xxx
database_url: postgresql://...Virtual Key 与租户隔离#
AI Gateway 的核心能力是 Virtual Key——每个业务线/团队独立的 API Key,绑定模型白名单、预算、限流。
# 为业务线创建 Virtual Key
curl http://litellm:4000/key/generate \
-H "Authorization: Bearer sk-master-xxx" \
-d '{
"key_alias": "team-nlp-prod",
"models": ["gpt-4o-mini", "llama-70b-internal"],
"max_budget": 500.0,
"budget_duration": "30d",
"tpm_limit": 100000,
"rpm_limit": 500,
"metadata": {"team": "nlp", "env": "prod"}
}'业务方用返回的 sk-xxx 直接当 OpenAI Key 用,网关自动完成鉴权、限流、计费、审计。
Virtual Key 的多维控制:
| 维度 | 配置 | 作用 |
|---|---|---|
| 模型白名单 | models | 限制可调用的模型 |
| 预算上限 | max_budget + budget_duration | 30 天最多花 500 美元 |
| RPM 限流 | rpm_limit | 每分钟最多 500 请求 |
| TPM 限流 | tpm_limit | 每分钟最多 100K token |
| 元数据 | metadata | 团队/环境标签,用于成本归因 |
模型路由策略#
请求 → Gateway
├─ 鉴权(Virtual Key → 可用模型白名单)
├─ 路由决策
│ ├─ cost-based:选最便宜的
│ ├─ latency-based:选历史延迟最低的
│ ├─ usage-based:选当前负载最低的
│ └─ kv-aware:选 KV Cache 命中最长的节点
├─ Fallback(如果主模型不可用)
└─ 限流(超过 RPM/TPM → 拒绝或排队)Model Alias 设计:
# 业务侧用语义化别名,底层模型可替换
fast-small: gpt-4o-mini / qwen-turbo / llama-8b
fast-medium: gpt-4o / qwen-max / llama-70b
smart: claude-sonnet / gpt-5.5 / deepseek-v4
local-only: vllm-internal(不 fallback 到公网)业务侧代码只引用 alias(如 fast-medium),底层模型升级/切换/降本时网关层改配置,业务无感知。
稳定性能力#
限流#
# LiteLLM 支持三级限流
tpm_limit: 100000 # tokens per minute
rpm_limit: 500 # requests per minute
max_budget: 500.0 # 预算上限(美元/30天)限流策略选择:
- RPM 限流:防止单租户刷爆 QPS
- TPM 限流:防止长 prompt 烧光算力
- 预算限流:防止成本失控(30 天 500 美元用完即拒)
限流优先于扩容:遇到流量峰值先限流保护已有服务,等扩容完成再放开。直接扩容可能扩容还没完成服务已经被打挂。
熔断与 Fallback#
router_settings:
fallbacks:
- gpt-4o-mini: ["claude-sonnet", "qwen-max"]
context_window_fallbacks:
- gpt-4o-mini: ["claude-sonnet"] # prompt 超长时自动兜底
allowed_fails: 3 # 失败 N 次进入冷却
cooldown_time: 60 # 冷却 60 秒熔断规则:
- HTTP 5xx、连接失败、timeout → 触发切 fallback
- 连续失败超过
allowed_fails→ 进入冷却,暂停分配 - 冷却期过后逐步恢复,避免雪崩
Fallback 链设计:
主模型:gpt-4o-mini(便宜,快)
├─ fallback 1:claude-sonnet(贵但稳)
└─ fallback 2:qwen-max(国产备选)
注意:fallback 模型可能更贵,不要兜底到比主模型贵 10x 的模型上超时与重试#
router_settings:
num_retries: 2 # 重试次数(只对 5xx,4xx 不重试)
timeout: 30 # 单次请求超时(秒)超时设计:
- 流式输出 timeout 要给够(输出 500 token 可能要 30s+)
- 非 5xx 错误不重试(4xx 是业务错误,重试无用)
- 重试要指数退避,避免雪崩
灰度发布#
模型灰度发布的典型流程:
v1 模型(在线) v2 模型(新版本)
│ │
├─ 90% 流量 ─────────────────────┤
└─ 10% 流量 ─────────────────→ │
│
观察 TTFT/TPOT/质量
无异常 → 逐步提升到 100%
有异常 → 回滚实现方式:
- 网关级:路由规则按比例分流(如 LiteLLM 的
rpm_limit分配) - 引擎级:Triton 的
version_policy: { specific: { versions: [1, 2] } }配合客户端指定版本 - K8s 级:两个 Deployment + Service 权重
灰度策略:
- 按比例灰度(10% → 50% → 100%)
- 按租户灰度(先内部团队 → 再小客户 → 最后大客户)
- 按地域灰度(先小地区 → 再大地区)
回滚#
在模型发布出现问题时:
- 网关切回老模型后端(最快,几秒生效)
- K8s 回滚到前一版本 Deployment
- Triton 卸载新版、加载旧版 engine
回滚的核心前提是:老版本的模型/engine 仍在集群中可用。不要发布完就删老版本。建议保留最近 3 个 production 版本。
弹性伸缩#
HPA:按 GPU 指标伸缩(非 CPU)#
传统 HPA 按 CPU 扩缩,但 LLM 推理的瓶颈是 GPU。需要 GPU 指标的 HPA:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: vllm-hpa
spec:
scaleTargetRef:
name: vllm-deployment
minReplicas: 2
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: vllm_num_requests_waiting # 排队请求数
target:
type: AverageValue
averageValue: "10"
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 85为什么不用 CPU 指标:LLM 推理的 CPU 使用率和实际负载关系弱。tokenizer 和 sampling 用 CPU,但瓶颈在 GPU。用 num_requests_waiting 或 GPU SM 利用率作扩缩指标。
KEDA:事件驱动伸缩#
KEDA(Kubernetes Event-Driven Autoscaling)更适合批处理和自定义指标场景:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: vllm-keda
spec:
scaleTargetRef:
name: vllm-deployment
minReplicaCount: 1
maxReplicaCount: 10
cooldownPeriod: 300 # 缩容冷却 5 分钟
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus:9090
metricName: vllm_queue_depth
query: vllm:num_requests_waiting
threshold: "5"KEDA vs HPA:
- HPA 只能用 metrics.k8s.io 和 custom.metrics.k8s.io
- KEDA 支持 Prometheus、Kafka、Redis、AWS CloudWatch 等 60+ 数据源
- KEDA 支持 scale-to-zero(HPA 不支持)
Scale-to-Zero#
空闲时把推理实例缩到零,有请求时再启动。适合非实时、低频调用的模型:
# KServe + KEDA 实现 scale-to-zero
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
spec:
predictor:
minReplicas: 0 # 允许缩到零
maxReplicas: 5
scaleTarget: 0
scaleMetric: concurrency代价:模型从零启动需要加载权重(3-10 分钟),第一个请求超时。
冷启动优化:
冷启动超时
├─ 模型加载时间:70B 模型约 3-5 分钟
├─ 优化方案:
│ ├─ 权重预缓存到本地 NVMe(不从 NFS 加载)
│ ├─ keep-warm 至少 1 副本(不完全 scale-to-zero)
│ ├─ startupProbe 给足够时间(failureThreshold > 60)
│ ├─ 客户端 timeout 匹配(不要 30s 就超时)
│ └─ 预热请求(启动后先发一个短 prompt 预热 KV Cache 和 CUDA Graph)
└─ 权衡:不完全 scale-to-zero vs 冷启动延迟Scale-to-Zero 适用场景:
- 低频调用的内部工具模型(每天几十次请求)
- 开发测试环境的模型
- 非实时的批处理 API
不适用场景:
- 用户实时对话(冷启动超时不可接受)
- 高 QPS 生产服务(频繁扩缩成本高)
GPU-aware 扩缩指标#
| 指标 | 来源 | 阈值 | 扩缩动作 |
|---|---|---|---|
vllm:num_requests_waiting | vLLM metrics | > 10 | 扩容 |
| GPU SM 利用率 | DCGM Exporter | > 85% | 扩容 |
| GPU 显存占用 | DCGM Exporter | > 92% | 扩容 |
| KV Cache 使用率 | vLLM metrics | > 90% | 扩容 |
| GPU SM 利用率 | DCGM Exporter | < 20% 持续 30min | 缩容 |
可观测体系#
系统指标#
| 层级 | 指标 | 来源 | 告警阈值 |
|---|---|---|---|
| 请求级 | TTFT / TPOT / e2e latency | vLLM/SGLang metrics | P95 > SLA |
| 请求级 | Queue Length / num_running | vLLM/SGLang metrics | waiting > 10,5min |
| 资源级 | GPU 利用率 / 显存 / 温度 | DCGM Exporter | util < 20% / mem > 95% |
| 通信级 | NCCL 带宽 / 错包 | DCGM + NCCL | 错包 > 0 立刻告警 |
| 引擎级 | Batch Size / KV Cache Usage | vLLM metrics | KV > 90% |
成本指标#
- 单请求成本:
prompt_tokens × input_price + completion_tokens × output_price - 单 token 成本:按模型拆分
- 租户维度成本:按 Virtual Key / Team 聚合
- 模型维度成本:按底层模型拆分
-- LiteLLM SpendLogs 按团队 × 模型的花费矩阵
SELECT
metadata->>'team' AS team,
model,
SUM(spend) AS spend,
SUM(total_tokens) AS tokens
FROM "LiteLLM_SpendLogs"
WHERE startTime > NOW() - INTERVAL '30 days'
GROUP BY 1, 2 ORDER BY spend DESC;
-- GPU 闲置成本
SELECT
node,
(1 - AVG(gpu_utilization)) * gpu_hourly_cost AS idle_cost
FROM dcgm_metrics
GROUP BY 1;效果指标(2026 新增)#
模型服务质量不仅看延迟和成本,还要看输出质量:
- 质量漂移:同一批 benchmark prompt,对比新旧版本模型输出的差异
- 幻觉检测:对 RAG 场景,检测生成内容是否与检索文档一致
- 在线采样评估:对生产流量随机采样,人工或自动评估质量
效果指标采集方法:
1. 离线评测:定期跑 benchmark(MMLU/HumanEval/C-Eval)
2. 在线采样:1% 生产流量 → 自动评分(LLM-as-a-Judge)
3. RAG 一致性:生成内容 vs 检索文档的 NLI(自然语言推理)分数
4. 用户反馈:点赞/点踩 → 质量信号OpenTelemetry GenAI 语义约定(2026 现状)#
截至 2026 年,OpenTelemetry 的 GenAI 语义约定大部分仍处于 Experimental/Development 状态(尚未 stable、属性名仍可能变动),但已成为 LLM 可观测的事实对齐方向。它大致可分为六层属性:
L1: GenAI 系统(system, model, provider)
gen_ai.system: "vllm"
gen_ai.request.model: "qwen2.5-72b"
gen_ai.provider: "litellm"
L2: 请求属性(max_tokens, temperature, top_p)
gen_ai.request.max_tokens: 1024
gen_ai.request.temperature: 0.3
gen_ai.request.top_p: 0.9
L3: Token 用量(input_tokens, output_tokens, total_tokens)
gen_ai.usage.input_tokens: 150
gen_ai.usage.output_tokens: 320
gen_ai.usage.total_tokens: 470
L4: 响应属性(finish_reasons, response_id)
gen_ai.response.finish_reasons: ["stop"] # 官方为数组
gen_ai.response.id: "chatcmpl-xxx"
L5: 成本属性(注意:OTel 官方约定目前并无 cost 语义属性,
以下为 LiteLLM 等厂商的自定义扩展,跨系统不保证一致)
gen_ai.response.cost.amount: 0.0023 # 非官方
gen_ai.response.cost.currency: "USD" # 非官方
L6: Agent/MCP 工具调用(tool_name, tool_call_id, mcp_server)
gen_ai.tool.name: "search_web"
gen_ai.tool.call.id: "call_xxx"
gen_ai.tool.mcp.server: "mcp-search"标准化的意义:不同的推理引擎(vLLM/SGLang/TRT-LLM)、不同的中间件(LiteLLM/LangChain),只要遵循 OTel GenAI 约定,就能统一接入 Jaeger/Tempo 做链路追踪,Prometheus 做指标采集。不用为每个引擎写自定义 instrument。
接入方式:
# vLLM 启动时启用 OTel
vllm serve Qwen/Qwen2.5-72B-Instruct \
--otlp-traces-endpoint http://otel-collector:4317
# LiteLLM Proxy 配置 OTel
litellm_settings:
otel:
endpoint: http://otel-collector:4317
service_name: litellm-proxy监控技术栈#
| 组件 | 用途 | 采集内容 |
|---|---|---|
| DCGM Exporter | GPU 指标 | SM 利用率、显存、温度、功耗、NVLink 带宽、ECC |
| vLLM/SGLang /metrics | 推理引擎指标 | TTFT、TPOT、tokens/s、queue、KV Cache 使用率 |
| LiteLLM /metrics | 网关指标 | QPS、Spend、Error rate、model/team 维度 |
| Prometheus | 指标存储 | 所有上述指标 |
| Grafana | 可视化 | Dashboard 面板 + 告警规则 |
| Loki / ELK | 日志聚合 | 推理请求日志、错误日志 |
| Jaeger / Tempo | 链路追踪 | OTel GenAI trace |
| Langfuse | LLM 调用审计 | Prompt + Response + Token 全量记录 |
告警规则示例#
# GPU 温度过高
- alert: GPUHighTemperature
expr: DCGM_FI_DEV_GPU_TEMP > 85
for: 5m
labels:
severity: warning
annotations:
summary: "GPU {{ $labels.gpu }} 温度过高"
# KV Cache 接近用满
- alert: KVCacheAlmostFull
expr: vllm:gpu_cache_usage_perc > 0.95
for: 10m
labels:
severity: critical
# 请求排队超过阈值
- alert: VLLMHighQueueDepth
expr: vllm:num_requests_waiting > 20
for: 1m
labels:
severity: warning
# P99 TTFT 超过 SLA
- alert: HighP99TTFT
expr: histogram_quantile(0.99, vllm:time_to_first_token_seconds_bucket) > 10
for: 2m
labels:
severity: critical
# 单 Team 日消费异常
- alert: LLMDailyCostSpike
expr: increase(litellm_spend_metric[1h]) / increase(litellm_spend_metric[1h] offset 1d) > 3
for: 10m
labels:
severity: warning
# NCCL 错包(硬件故障信号)
- alert: NCCLErrorCount
expr: increase(nccl_errors_total[5m]) > 0
labels:
severity: critical实战要点#
AI Gateway 是必须的,不是可选的:不到网关层做统一接入,多模型、多团队、成本统计、安全审计都是空谈。LiteLLM 是开源首选。
限流优先于扩容:遇到流量峰值先限流保护已有服务,等扩容完成再放开。直接扩容可能扩容还没完成服务已经被打挂。
熔断 fallback 链路要测试:fallback 到的模型可能更贵,不要兜底到比主模型贵得多的模型上。fallback 模型可能被打爆——监控 fallback 模型的 QPS。
HPA 用 GPU 指标而非 CPU:LLM 推理的 CPU 使用率和实际负载关系弱。用
num_requests_waiting或 GPU 利用率作扩缩指标。OpenTelemetry GenAI 语义约定是 2026 的对齐方向(多数属性仍 experimental、未 stable):新项目可观测设计直接对齐它,省去大量自定义 instrument 工作。六层属性覆盖系统/请求/Token/响应/成本/Agent 工具调用——但要注意"成本"属性并非官方约定,需用厂商自定义扩展。
成本指标是治理的基础:没有「谁花了多少钱」的数据,成本优化就是盲人摸象。按 Team/Model/Feature 维度拆分,配预算告警。
Scale-to-Zero 要权衡冷启动:低频模型可以 scale-to-zero 省成本,但第一个请求会超时。keep-warm 1 副本是折中方案。
效果可观测不能省:只看延迟和成本不看质量,模型劣化发现不了。RAG 场景的幻觉检测、定期 benchmark 评测是在线质量保障的底线。
灰度必须可回滚:灰度期间保留老版本权重一直到新版本稳定至少 1 周。回滚要秒级见效(网关层切流量)。
审计日志要全:LLM 调用的 Prompt + Response + Token + Cost 全量记录,合规抽查时这是唯一凭据。
小结#
线上稳定性与可观测的核心能力矩阵:
AI Gateway(鉴权/路由/隔离/额度/审计)
↓
稳定性(限流/熔断/fallback/超时/重试/灰度/回滚)
↓
弹性伸缩(HPA(KEDA) / scale-to-zero / 冷启动 / GPU-aware 指标)
↓
可观测(系统指标 + 成本指标 + 效果指标)
↓
技术栈(OTel GenAI / DCGM / Prometheus / Grafana / Loki / Jaeger / Langfuse)2026 年的关键认知:
- OTel GenAI 语义约定是 LLM 可观测的对齐方向(多数属性仍 experimental、无官方 cost 属性),新项目可提前对齐
- Scale-to-Zero让低频模型成本可控,但冷启动要预留优化
- 效果可观测(质量/幻觉)是与传统 DevOps 可观测的最大区别
- AI Gateway是 LLM 服务化的统一入口,不是可选组件
下一章进入 模型工程化与平台治理——Model Registry、Eval Pipeline、国内合规备案、内容安全。