LLM 推理延迟监控体系:从 Metrics 采集到 SLO 驱动的告警策略
一、推理延迟的"分阶段视角"——为什么均值无法反映真实用户体验
大模型推理的延迟由多个阶段叠加而成,每一阶段都有不同的工程瓶颈和优化手段。将"推理延迟"作为一个整体指标监控,就像用平均气温描述一年的气候——严重的局部恶化会被平均消解。
监控体系必须从分阶段延迟入手:请求排队时间(Queue Time)、首 Token 延迟(TTFT)、单 Token 生成延迟(TPOT)、以及 Token 间抖动(Token Interval Variance)。这四个指标共同构成推理延迟的完整画像,任何一个的劣化都能指向不同层面的问题。
二、推理延迟的四阶段分解与监控埋点
flowchart LR A[客户端发起请求] -->|t0| B[负载均衡/LB<br/>网络延迟 1~3ms] B -->|t1| C[推理引擎请求队列<br/>Queue Time<br/>排队等待] C -->|t2| D[Pre-fill 阶段<br/>TTFT<br/>并行处理 Prompt Tokens] D -->|t3| E["Decode 阶段<br/>Token 1"] E -->|t4| F["Token 2"] F -->|t5| G["..."] G -->|tn| H["流式返回结束<br/>Total Time = tn - t0"] subgraph 延迟分解 D --> D1["TTFT = t3 - t2<br/>(受 Prompt 长度 + Batch 影响)"] E --> E1["TPOT = mean(t4-t3, t5-t4, ...)<br/>(受 Decode Batch 大小 + KV Cache 影响)"] C --> C1["Queue Time = t2 - t1<br/>(受 max-num-seqs + 当前负载影响)"] end三、Prometheus + vLLM Metrics 的监控实现
vLLM 通过/metrics端点暴露 Prometheus 格式的指标,以下为核心监控指标与告警规则:
# Prometheus 告警规则:推理服务 SLO 监控 groups: - name: llm_inference_slo interval: 30s rules: # 告警 1: TTFT 尾延迟超过 3 秒 - alert: HighTTFTTailLatency expr: | histogram_quantile(0.99, rate(vllm:time_to_first_token_seconds_bucket[5m]) ) > 3.0 for: 5m labels: severity: warning annotations: summary: "TTFT P99 > 3s,可能 Batch 过大或 GPU 利用饱和" # 告警 2: TPOT 尾延迟超过 50ms(交互式聊天阈值) - alert: HighTPOTTailLatency expr: | histogram_quantile(0.99, rate(vllm:time_per_output_token_seconds_bucket[5m]) ) > 0.05 for: 5m labels: severity: warning annotations: summary: "TPOT P99 > 50ms,交互式体验劣化" # 告警 3: 请求排队时间过长——engine 饱和信号 - alert: HighQueueTime expr: | avg(vllm:request_queue_time_seconds) > 2.0 for: 2m labels: severity: critical annotations: summary: "请求排队时间 > 2s,max-num-seqs 或显存容量不足" # 告警 4: GPU 利用率持续饱和 - alert: GPUSaturation expr: | avg(nvidia_gpu_utilization{gpu="H800"}) > 95 for: 10m labels: severity: warning annotations: summary: "GPU 平均利用率 > 95% 持续 10min——扩容或限流" # 告警 5: KV Cache 使用率接近物理上限 - alert: HighKVCacheUsage expr: | vllm:gpu_cache_usage_ratio > 0.90 for: 5m labels: severity: critical annotations: summary: "KV Cache 使用率 > 90%,即将 OOM 拒绝请求"延迟指标的采集和聚合策略:
# Python 侧:请求级别的延迟埋点——附加标签用于多维分析 import time from contextlib import contextmanager from prometheus_client import Histogram # 定义分阶段延迟直方图——桶边界对齐推理场景的典型值 ttft_hist = Histogram( 'llm_ttft_seconds', 'Time To First Token', labelnames=['model', 'dtype'], buckets=[0.05, 0.1, 0.2, 0.5, 1.0, 2.0, 5.0, 10.0, 30.0] ) tpot_hist = Histogram( 'llm_tpot_seconds', 'Time Per Output Token', labelnames=['model', 'dtype'], buckets=[0.01, 0.015, 0.02, 0.025, 0.03, 0.05, 0.1, 0.2] ) queue_hist = Histogram( 'llm_queue_seconds', 'Queue Waiting Time', buckets=[0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 30.0] ) @contextmanager def observe_llm_latency(model: str, dtype: str): """请求级延迟上下文管理器——自动分段记录""" t_req = time.time() t_queue = t_req yield t_queue # 调用方设置 t_queue = time.time() 标记入队时刻 end = time.time() queue_time = t_queue - t_req if t_queue > t_req else 0 queue_hist.labels(model=model, dtype=dtype).observe(queue_time) # 使用示例: # with observe_llm_latency("llama-3.1-70b", "bf16") as tq: # tq = time.time() # 请求入队 # # ... 推理执行 ...四、监控的几个关键工程挑战
TTFT 与 TPOT 的内在耦合:增大 Batch Size 可以降低 TPOT(GPU SM 更饱满),但同时增加 TTFT(Pre-fill 需要处理更多 prompt)。如果max-num-seqs设置过高,TTFT 劣化会迁移到用户感知层面。监控规则必须同时对两个指标设阈值——单一指标健康不代表服务水平健康。
流式响应的尾部延迟偏差:SSE 流式传输中,少数 Token 的生成延迟突然飙升(如遇到高熵 token),但总体 P50 仍然平稳。仅监控均值或 P50 会掩盖这类延迟毛刺。P99 和最大延迟的监控必须同时存在,且告警阈值应区分低频毛刺(10 秒内一次)和持续劣化(5 分钟以上)。
Prometheus 直方图的桶边界选择:Histogram 的 bucket 边界决定了分位数的估算精度。TTFT 的桶应从 50ms 延伸到 30s;TPOT 从 10ms 到 200ms。不当的桶边界会导致 P99 估算值与真实值偏差 20%~30%。每次 GPU 硬件升级或模型版本变更后,应先运行一次分桶分析来调整边界。
五、总结
LLM 推理延迟监控的核心是分阶段采集——TTFT、TPOT、Queue Time 必须作为独立指标分别追踪,三者劣化的根因完全不同(TTFT→Pre-fill 计算压力、TPOT→Decode Batch/显存带宽、Queue Time→并发超限)。Prometheus Histogram + vLLM /metrics 端点构成标准监控组合。
告警策略应以 SLO 为锚点:交互式聊天(TTFT P99 < 3s, TPOT P99 < 50ms)、代码补全(TTFT P99 < 500ms, TPOT P99 < 30ms)、批量分析(TTFT P99 < 30s, TPOT P99 < 200ms)。监控不是告警的终局——它应该是性能回归分析的起点,每次告警都应关联到同时段的硬件指标(GPU 温度/功耗/时钟频率)以定位根因。