AI 推理运维学习路径:从 GPU 节点、vLLM 与显存,到吞吐延迟、RAG、评估与成本
使用方式
AI 推理运维和传统后端值班的差别在于资源约束更硬:显存、算力、带宽和模型加载时间决定了服务能不能起、能扛多少并发、一次扩容要等多久。这条路径按“节点 → 引擎 → 性能 → 质量与成本”的线上链路组织。
四个阶段建议在单卡机器或测试集群完成,不要在共享训练集群上做破坏性实验:
- 先读:始终把现象归到四类资源之一:显存、算力、带宽、调度。
- 再做:每次只改一个参数,记录模型、输入输出长度、并发、量化和结果。
- 后测:留下可复现的测量记录和回滚参数,而不是只留一个“调好了”的结论。
AI 服务的“正常”不只看进程存活,还要看首 token 延迟、单 token 延迟、排队、显存水位和单位 token 成本。
阶段一:GPU 节点与集群资源
目标:能确认 GPU 是否可见、驱动与运行时是否匹配、节点是否健康、MIG 与设备插件是否正确暴露资源,以及多卡通信是否正常。
阅读顺序:
- nvidia-smi — 显存、利用率、进程、ECC 和 Xid 状态。
- gpu-xid — 从内核日志定位掉卡、ECC 和硬件复检。
- gpu-burn — 用压力测试验证新节点和疑似故障卡。
- dcgm-exporter — GPU 指标采集、告警和 Prometheus 集成。
- gpu-operator — 驱动、容器运行时、设备插件和监控的一体化部署。
- nvidia-device-plugin — 把 GPU 作为可调度资源暴露给 Pod。
- gpu-mig — 把一张 GPU 切成多个隔离实例并按 profile 分配。
- gpu-node-lifecycle — 节点加入、下线、驱动升级和重新调度的检查清单。
- nccl-tests — 用 all-reduce 和 all-gather 验证 NVLink、PCIe 与 IB 带宽。
- nccl-hang — 集合通信卡死时区分初始化、网络、拓扑和 slow rank。
动手任务:挑一个测试 GPU 节点,完成“可见性 → 健康 → 调度 → 通信”四项检查:确认驱动和 CUDA 版本,跑一次短时 gpu-burn,查看 DCGM 指标,提交一个申请 1 张 GPU 的 Pod,最后跑一次两卡 NCCL 测试。再模拟一次节点下线,确认 Pod 能被重新调度。
nvidia-smi --query-gpu=index,name,driver_version,memory.total,memory.used,ecc.mode.current --format=csv
nvidia-smi -q -d ECC,XID | grep -iE 'pending|error|xid'
curl -s localhost:9400/metrics | grep -E 'DCGM_FI_DEV_(GPU_UTIL|FB_USED|XID)'
kubectl get nodes -l nvidia.com/gpu.present=true
kubectl describe node <gpu-node> | grep -A3 'nvidia.com/gpu'
kubectl drain <gpu-node> --ignore-daemonsets --delete-emptydir-data --dry-run=client
mpirun -np 2 all_reduce_perf -b 8 -e 128M -f 2 -g 1
过关标准:
- 能解释驱动版本、CUDA 运行时版本和框架编译版本的兼容关系。
- 能根据 Xid、ECC、温度和利用率判断是硬件、驱动、散热还是负载问题。
- 知道 GPU 利用率 100% 不等于有效吞吐高,还要看显存、带宽和排队。
- 能验证 MIG 切分后的资源数量、显存和隔离边界,不会把整卡和切片混用。
- 多卡变慢时能区分通信、数据加载、负载不均和 slow rank。
阶段二:vLLM、显存与 OOM
目标:能把模型部署成 OpenAI 兼容服务,区分启动 OOM、运行中 KV Cache OOM 和容器内存 OOM,并在不牺牲稳定性的前提下调整显存与并发参数。
阅读顺序:
- vllm — PagedAttention、连续批处理和 OpenAI 兼容接口。
- vllm-oom — 权重、KV Cache、并发配置、泄漏和节点内存 OOM 的分层排查。
- vllm-tuning — 显存预算、批处理参数、前缀缓存和并行度的调优顺序。
- model-load-failed — 权重路径、权限、量化兼容、自定义代码和 GPU 可见性。
- sglang — RadixAttention、前缀缓存和高并发服务。
- vllm-vs-sglang — 两种高吞吐引擎的差异与选型。
- openai-api-compatible — 不同引擎的端点、字段和兼容性差异。
- quantization — bitsandbytes、AWQ、GPTQ 与 FP8 的显存和精度取舍。
- fp8-inference — 在 Hopper/Ada 上用 FP8 降低显存和带宽压力。
- tensorrt-llm — 编译优化、量化内核和 NVIDIA 平台上的替代方案。
动手任务:用 vLLM 部署一个小模型,记录启动日志里的显存账本;用不同 max-model-len 和并发各压测一次,观察 KV Cache 使用率和 waiting 队列;再故意把 gpu-memory-utilization 调高或把上下文调长,制造一次 OOM,判断它属于哪一类。
vllm serve Qwen/Qwen2.5-1.5B-Instruct --port 8000 --max-model-len 4096 --gpu-memory-utilization 0.85
curl -s http://localhost:8000/v1/models
curl -s http://localhost:8000/metrics | grep -E 'kv_cache|num_requests_(running|waiting)|gpu_cache'
nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csv -l 1
kubectl describe pod <pod> | grep -A8 'Last State'
dmesg -T | grep -iE 'oom|killed process'
过关标准:
- 能说出显存由权重、KV Cache、激活和框架临时缓冲区哪些部分组成。
- 能区分启动即失败、运行中 CUDA OOM 和容器 OOMKilled 三种现象及各自第一检查点。
- 知道 KV Cache 随并发、上下文长度和层数增长,减并发和上下文通常比减 batch 更直接。
- 调参一次只动一项,并记录 TTFT、TPOT、吞吐、错误率和显存水位。
- 量化方案有精度回归结果,不把“更小、更快”直接等同于“可以上线”。
阶段三:吞吐、延迟、扩缩容与调度
目标:能把“回答变慢”拆成 TTFT、TPOT、排队、网络和 GPU 争用,判断该优化单副本、加副本、改调度还是改客户端,并让扩缩容指标真正代表瓶颈。
阅读顺序:
- inference-latency — TTFT、TPOT、排队、KV Cache、网络和 GPU 的分层定位。
- inference-autoscaling — HPA/KEDA、排队与并发、冷启动、GPU 容量和缩容抖动。
- ray-scheduling — Ray 任务与 GPU Pending,分清 Kubernetes 和 Ray 两层调度。
- keda — 按队列、并发等事件指标驱动扩缩容。
- hpa — 指标链路、目标值和扩缩容行为。
- speculative-decoding — 用草稿模型或 n-gram 预测加速 decode。
- vllm-lora — 一个基座模型动态挂载多个适配器,按请求路由。
- triton — 多框架模型仓库、动态批处理和并发实例。
- kueue — 批处理作业排队、配额和 GPU 资源公平分配。
动手任务:用固定数据集和固定输入输出长度,分别在 1、5、20 并发下压测同一个 vLLM 服务,记录 TTFT、TPOT、吞吐、waiting 和 GPU 利用率;再制造一次 Pod Pending,判断阻塞在 GPU 资源、配额、污点还是调度器。最后用队列或并发指标配置一次扩缩容并观察冷启动时间。
vllm bench serve --backend openai-chat --base-url http://localhost:8000 --endpoint /v1/chat/completions --model qwen --dataset-name random --random-input-len 1024 --random-output-len 256 --num-prompts 500 --request-rate 20
curl -s http://localhost:8000/metrics | grep -Ei 'ttft|tpot|itl|waiting|running|kv_cache'
kubectl get hpa -A
kubectl describe hpa <name> -n <namespace>
kubectl get pods -n <namespace> -o wide | grep Pending
kubectl describe pod <pending-pod> -n <namespace> | tail -30
过关标准:
- 能分别解释 TTFT 高、TPOT 高和端到端慢对应的不同瓶颈。
- 扩缩容指标能代表排队或并发,而不是 CPU;扩容后吞吐确实上升,单副本不持续排队。
- 知道冷启动包含镜像拉取、模型下载、编译和预热,并把它计入扩容决策。
- Pending 时先看事件、配额、污点、亲和性和 GPU 可分配数量,而不是重启工作负载。
- 优化前后使用同一数据集、同一请求速率和同一输出长度,结论可复现。
阶段四:RAG、评估与成本
目标:能在“答非所问”时按检索链路分层定位,用离线评估和线上追踪验证改动,并把 GPU、token 和存储成本拆到可解释的单位。
阅读顺序:
- rag-retrieval-quality-incident — 从切分、向量化、索引、权限过滤到生成的分层定位。
- rag-production-checklist — 检索、生成、权限和上线的检查清单。
- ragas — 忠实度、回答相关性和上下文召回等 RAG 指标。
- lm-eval — 用标准基准做模型版本对比和回归。
- llm-as-judge — 用 rubric 和校准降低模型评审偏差。
- langfuse — 记录调用链、提示、token、延迟和在线反馈。
- embedding-model-migration — 维度、归一化、距离度量、索引重建和双写灰度。
- vector-db-selection — 按规模、过滤、混合检索、运维和成本选型。
- cost-optimization-checklist — 云与集群成本优化检查项。
- finops — 成本分摊、预算告警和优化优先级。
- opencost — 按命名空间和工作负载拆分 GPU 与集群成本。
动手任务:选 5 个“答非所问”的 bad case,逐层打印 query 改写、召回候选、重排后上下文和最终回答,判断问题在检索还是生成;用 Ragas 对改动前后各跑一次评估,再用 Langfuse 核对线上 token 和延迟;最后计算每千次请求的 GPU 与 token 成本。
curl -s -X POST "http://<ragflow-host>:9380/v1/api/retrieval" -H "Authorization: Bearer $RAGFLOW_API_KEY" -H 'Content-Type: application/json' -d '{"question":"<问题>","dataset_ids":["<DATASET_ID>"],"top_k":10}' | jq '.data.chunks[] | {score, document_id, content: .content[0:200]}'
lm_eval --model local-completions --model_args base_url=http://localhost:8000/v1/completions,model=qwen --tasks mmlu --batch_size 8
python evaluate.py --dataset eval.jsonl --metrics faithfulness,answer_relevancy,context_recall
过关标准:
- 能按“正确文档是否召回、排名、重排后是否保留、上下文是否有证据”判断问题层级。
- 检索评估和生成评估分开做,召回率低时不会先改生成提示或换更大模型。
- 每次模型、提示、embedding 或分块改动都有固定数据集的前后对比和回滚版本。
- 线上能按请求追踪 token、延迟、检索命中和用户反馈,出现回归能定位到版本。
- 成本报告能区分 GPU 空转、模型过大、重复回填、缓存未命中和按 token 计费带来的差异。
常见误区
- 只看 GPU 利用率,不看有效吞吐、显存水位、排队和 TTFT。
- 显存不够就无脑减 batch,却不检查 KV Cache、上下文长度、并发和内存碎片。
- 把量化模型当成无损替代,不做精度回归和任务差异评估。
- 一次同时改多个参数,吞吐变了也说不清是哪一项生效。
- 用 CPU 使用率给推理服务做 HPA,指标与真实瓶颈无关。
- 扩容后不检查冷启动和模型预热,新副本还没 Ready 就被继续加压。
- RAG 只调生成提示,不检查切分、embedding、索引和权限过滤。
- 用公开基准分数直接推断生产效果,忽略数据分布、污染和业务口径。
- 成本只看 GPU 单价,不看空转、超配、重复回填和存储生命周期。
参考链接
读完自测
合上页面,先回答,再展开对照。
- vLLM 报 OOM 时,如何区分启动失败、KV Cache 不足和容器内存超限?各自先改什么?
- 推理服务延迟升高,TTFT 和 TPOT 分别指向哪些瓶颈?为什么不能只看 GPU 利用率?
- RAG 出现“答非所问”,为什么要先看检索指标再看生成指标?如何设计一次可复现的回归?
答案
- 启动即失败通常发生在权重加载或 KV Cache 初始化,日志会给出模型最大长度与可用缓存块不匹配,先检查模型大小、量化兼容、
max-model-len 和 gpu-memory-utilization;运行中 CUDA OOM 多见于请求量、长上下文或突发并发把 KV Cache 打满,先看 waiting、KV Cache 使用率和并发,再降并发或上下文;退出码 137 或 OOMKilled 是容器或宿主机内存超限,先看 dmesg、cgroup 和应用内存,而不是 GPU 显存。
- TTFT 高通常是排队、长提示 prefill、tokenizer 或调度慢;TPOT 高或抖动通常是 decode、KV Cache 压力、批处理、投机解码或 GPU 争用;客户端首字慢而服务端 TTFT 正常,则查网络、代理缓冲和流式转发。GPU 利用率高只能说明卡在忙,不能说明有效 token 吞吐高,也不能区分排队和计算。
- RAG 的答案上限由召回上下文决定,正确文档没被召回时,改生成模型或提示只能让模型更会编。回归要固定问题集、文档版本、分块参数、embedding 版本、top-k、重排配置、模型和采样参数,分别记录 recall@k、MRR 或 nDCG、忠实度、回答相关性和引用正确率,改动前后用同一口径对比并保留回滚版本。
相关条目