27届大模型面试准备(七十八):大模型推理线上问题定位与根因分析工程——TTFT/TBT 抖动、OOM、吞吐跌零排查手册

27届大模型面试准备(七十八):大模型推理线上问题定位与根因分析工程------TTFT/TBT 抖动、OOM、吞吐跌零排查手册

引言

本文是系列第 78 篇。前两篇讲了高可用、容灾与多模态训练,这一篇聚焦一个所有上线模型都逃不掉的现实问题:线上推理出问题了,怎么在 10 分钟内定位根因。面试官非常喜欢拷问候选人的"故障排查肌肉记忆"------因为能背架构的人很多,能在凌晨三点对着监控曲线说出"这是 PD 分离后 KV 调度不均导致 TBT 长尾"的人很少。

一篇合格的推理工程简历,必须能讲清楚四类高频故障:TTFT(首 token 延迟)抖动、TBT(token 间延迟)长尾、OOM 显存溢出、吞吐跌零(throughput 突然掉到接近 0)。本篇给出可操作的排查链路与代码级诊断手段。

复制代码
线上推理问题定位总览
===========================================
           监控告警触发
                │
    ┌───────────┼───────────────┐
    ▼           ▼               ▼
 TTFT 抖动   TBT 长尾      吞吐跌零/OOM
    │           │               │
    ▼           ▼               ▼
 Prefill 侧   Decode 侧      资源/数据/调度
 排队/算子     KV/调度/批     瓶颈定位
    │           │               │
    └───────────┼───────────────┘
                ▼
         根因定位 → 止血 → 复盘

一、关键指标定义与采集

先把指标说清楚,否则排查无从谈起。

指标 含义 健康量级 用户感知
TTFT 首 token 延迟(请求到第一个 token) < 500ms(小模型) "响应快不快"
TBT token 间延迟(解码步间隔) < 50ms(实时) "打字流不流畅"
TPOT 每 output token 时间 同 TBT 同 TBT
E2E 延迟 整句完成时间 TTFT + n*TBT 总耗时
QPS/吞吐 每秒请求/生成 token 数 视资源 成本与容量
批大小 同批并发序列数 动态 显存占用

采集方式:在推理框架里对每个请求打点(request_id、enqueue_time、first_token_time、last_token_time),用 Prometheus 暴露 histogram,Grafana 看分位数(p50/p90/p99)。一定要看 p99 而不是均值------均值掩盖长尾。

复制代码
import time, prometheus_client as pc

HIST_TTFT = pc.Histogram("llm_ttft_ms", "Time to first token", buckets=[100,300,500,1000,2000])
HIST_TBT  = pc.Histogram("llm_tbt_ms", "Inter-token latency", buckets=[10,30,50,100,200])

class ReqTracer:
    def __init__(self, req_id):
        self.req_id = req_id
        self.t_enq = time.time()
        self.t_first = None
    def on_first(self):
        self.t_first = time.time()
        HIST_TTFT.observe((self.t_first - self.t_enq) * 1000)
    def on_step(self, t_prev, t_now):
        HIST_TBT.observe((t_now - t_prev) * 1000)

二、TTFT 抖动排查

TTFT 高通常卡在 Prefill 阶段。根因分布:

复制代码
TTFT 高
 ├─ 请求排队(并发>容量)
 │    看调度队列深度、排队时长直方图
 ├─ Prefill 算子慢(长 prompt、未切分)
 │    看 prompt token 数分布、attention 是否用 flash
 ├─ 冷启动 / 模型未预热
 │    看实例刚起/刚扩的时段
 └─ 批调度策略激进导致大请求阻塞小请求
      看 chunked prefill 是否开启

最容易被忽略的一点:长 prompt 的 Prefill 是计算密集且不可抢占的,一个 8k token 请求 Prefill 可能要几百毫秒,会直接拖高同窗口所有请求的 TTFT。解法:开启 chunked prefill(把 Prefill 切成小块与 Decode 交织),或用 PD 分离把 Prefill 和 Decode 放到不同实例池。

复制代码
# vLLM 开启 chunked prefill(示意)
# 启动参数
--enable-chunked-prefill \
--max-num-batched-tokens 8192 \
--scheduler-policy fcfs

三、TBT 长尾排查

TBT 高卡在 Decode 阶段 。Decode 每步只算一个新 token,计算量小但受 KV Cache 带宽和批大小支配。根因:

根因 信号 解法
批内混入超长序列,KV 挤占带宽 同批 max_len 远高于均值 按长度分组调度
KV Cache 碎片化 显存够但申请失败 换 paged/prefix cache
调度不均(PD 分离后 KV 传输慢) Decode 实例等 KV 优化 KV 传输/本地化
某卡降频/掉速 单卡 TBT 明显偏高 查 NVML 温度/功耗
采样 top-p 高导致核函数慢 高 top-p 时变慢 降 top-p/用投机解码
复制代码
# 用 pynvml 巡检单卡降频(TBT 长尾时逐个卡排查)
import pynvml
pynvml.nvmlInit()
for i in range(pynvml.nvmlDeviceGetCount()):
    h = pynvml.nvmlDeviceGetHandleByIndex(i)
    util = pynvml.nvmlDeviceGetUtilizationRates(h)
    clk = pynvml.nvmlDeviceGetClockInfo(h, pynvml.NVML_CLOCK_SM)
    pwr = pynvml.nvmlDeviceGetPowerUsage(h) / 1000.0
    print(f"gpu{i} util={util.gpu}% sm_clk={clk}MHz pwr={pwr}W")
# 某卡 sm_clk 远低于其他卡 => 降频/掉速,是 TBT 长尾元凶之一

四、OOM 显存溢出排查

OOM 是上线最常见的"硬故障"。多模态/长上下文尤其容易炸。定位清单:

复制代码
OOM 排查树
├─ 静态占用的 KV Cache 预留过大?
│    算:kv_bytes = 2 * n_layers * n_kv_heads * head_dim * seq * batch * dtype
│    下调 max_num_seqs / max_model_len
├─ 单请求超长(恶意/异常 prompt)?
│    设 max_input_len 上限 + 拒绝/截断
├─ 激活峰值(Prefill 大 batch)?
│    降 max_num_batched_tokens、开梯度无关的重算
├─ 碎片化导致"有总显存但无连续块"?
│    用 paged KV(vLLM/TSR 默认)、prefix cache 复用
└─ 多模型共卡?
      隔离部署或限制并发

def est_kv_bytes(n_layers, n_kv_heads, head_dim, seq, batch, dtype_bytes=2):
    per_tok = 2 * n_layers * n_kv_heads * head_dim * dtype_bytes  # K and V
    return per_tok * seq * batch

# 例:7B 模型 32层 32头 dim128, seq=4096, batch=64
print(est_kv_bytes(32, 32, 128, 4096, 64) / 1e9, "GB")
# 据此倒推 max_num_seqs,避免预留超显存

五、吞吐跌零排查

吞吐突然掉到接近 0,通常是"软死锁"而非硬件坏:

现象 根因 快速止血
请求全部卡住 调度死锁/某请求异常占批 超时踢出 + 重启 worker
QPS 为 0 但进程在 上游断流/健康检查误杀 查网关与探活配置
GPU 利用率 0 但显存满 KV 泄漏(请求未释放) 修请求生命周期,加 watchdog
吞吐阶梯下跌 扩缩容抖动/权重加载阻塞 预热 + 灰度发布

关键工程实践:给每个请求设硬超时与最大生成长度,并在请求结束时强制释放 KV 块,用 watchdog 监控"显存占用 vs 活跃请求数"的偏离度,偏离即告警。

复制代码
import asyncio

async def guarded_generate(req, max_tokens=2048, timeout=60):
    try:
        return await asyncio.wait_for(
            engine.generate(req, max_tokens=max_tokens), timeout=timeout)
    except asyncio.TimeoutError:
        engine.abort(req.req_id)          # 必须显式 abort 释放 KV
        raise TimeoutError(f"req {req.req_id} aborted after {timeout}s")

六、定位方法论总结

把上面串成一张"止血---定位---复盘"闭环:

复制代码
1. 看告警:哪个指标 p99 异常(TTFT/TBT/吞吐/OOM)
2. 切维度:按实例/卡/路由/用户维度下钻,找异常子集
3. 对变更:是否刚发布/扩容/改配置(时间相关性最强)
4. 抓现场:保留一个异常请求 trace + 对应卡监控快照
5. 止血:降级(限流/关特性/回滚)→ 根因 → 加防护(超时/配额)

面试速答

问:TTFT 高一般查什么?

答:先看是不是 Prefill 阶段排队(并发超容量)或长 prompt 未切分;再确认 chunked prefill / PD 分离是否开启;最后看实例冷启动。核心是 Prefill 计算密集且不可抢占,长请求会阻塞同窗口。

问:TBT 长尾但 GPU 利用率不低,为什么?

答:多半是批内混入超长序列挤占 KV 带宽,或某卡降频/掉速。用 pynvml 逐个卡看 SM 时钟和功耗,往往能抓到单卡异常。

问:OOM 但显存总量够,怎么回事?

答:KV Cache 碎片化------没有连续块可分配。用 paged KV(vLLM/TensorRT-LLM 默认)和 prefix cache 复用解决,并下调 max_num_seqs。

问:吞吐跌零怎么快速止血?

答:先确认是否请求级死锁/KV 泄漏,给请求加硬超时与 abort 释放;显存满但利用率 0 基本是 KV 泄漏,重启 worker 并修生命周期。

高频追问清单

  1. chunked prefill 和普通 prefill 在调度上有什么区别?对 TTFT/TBT 各有什么影响?
  2. PD 分离后 KV Cache 怎么跨节点传输?带宽瓶颈怎么估?
  3. paged KV 的碎片率怎么度量?什么负载下仍会碎片?
  4. 连续批处理(continuous batching)和静态批处理对长尾延迟影响?
  5. 投机解码引入后 TBT 抖动变大,可能是什么原因?
  6. 多租户下怎么给不同优先级请求做资源隔离与配额?
  7. 显存监控里"保留但无活跃请求"的 KV 怎么排查泄漏?
  8. 怎样设计请求级 trace,使一次慢请求可还原完整调度路径?
  9. 压测时怎么构造能暴露长尾的流量模型(泊松/突发)?
  10. 大促/峰值前怎么做容量评估与限流阈值设定?
相关推荐
程序猿编码4 天前
告别改源码适配模型:纯 C++ 可配置 LLM 推理引擎,全格式全结构兼容
c++·大模型·llm·推理引擎
蔡俊锋5 天前
华为昇腾 960 超节点发布:4096 卡、5500 个光引擎替 4.8 万光模块——国产算力拐点到了吗?
大模型·模型部署·ai架构·国产算力·华为昇腾
O。O蛋黄酥啊5 天前
Claude Code 记忆机制全拆解:Auto Memory 与 CLAUDE.md 双轨解析
大模型·agent·memory·claude·codex·记忆
BlackStar_L5 天前
第二章 上下文工程
大模型·llm·agent
User_芊芊君子5 天前
让 Claude Code 换上国产大脑:蓝耘元生代上 GLM-5.2 / DeepSeek / Qwen 模型横评实测
人工智能·ai·大模型
寻道码路5 天前
大模型工程化实战(十二):RAG 数据工程底座——采集到入库流水线(离线+在线双链路)
大模型·知识库·rag·ai工程化·llmops`·数据工程底座·文档采集
Web3&Basketball5 天前
CRM Agent 后训练实战:3 倍更少错误
python·架构·大模型·agent·推理
蚁小二官方5 天前
AI 安全治理框架更新|大模型训练数据合规,企业实操落地思路
大模型·数据合规·ai安全
AI模力圈5 天前
On-Policy Distillation:原理、变体与工程实现解析
大模型·强化学习·知识蒸馏
长谷深风1115 天前
根因定位:三步隔离法破解AIBadcase
人工智能·ai·大模型·retrieval·ai智能体·aiagent·aibadcase