news 2026/8/21 14:04:44

推理资源的预算方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
推理资源的预算方法

推理资源的预算方法

阅读说明:本文以推理服务中的典型故障链路说明排查和设计方法。文中的告警、数字与“线上”叙述如未给出来源,均应视为示例条件;落地前请在自己的版本、负载和资源约束下复测。

1. 业务高峰期的卡顿告警:8 卡 A100 显存全红与并发暴跌

下面用一个假设场景说明 推理服务 中应先检查哪些信号,以及如何验证判断。

晚高峰 20:30,Prometheus 告警钉钉群连续推送了 12 条 GPU 资源耗尽消息。线上部署的 Llama-3-70B 推理集群突然出现严重的 P99 延迟飙升,原本维持在 200ms 左右的首字延迟(TTFT)迅速冲到 4.5 秒,并发 Token 吞吐量从 3500 tokens/s 断崖式跌至 400 tokens/s。

登跳板机查看 kubectl top node,发现 4 台配备了 8 卡 A100-80G 的节点显存利用率全部处于 99.2% 的饱和状态。然而,用nvidia-smi深度观察,GPU-Util(算力利用率)却奇特地徘徊在 28%~35% 之间。这意味着算力没有用满,显存却被明显卡死。更糟糕的是,Kubernetes 的 HPA(Horizontal Pod Autoscaler)因为仅仅依赖 CPU 和通用显存占用指标,在并发骤增时触发了在未验证前扩容。由于大模型镜像高达 30GB 且权重加载耗时超过 3 分钟,新 Pod 还没准备好,原有的推理节点就已经因为 KV Cache 内存溢出(OOM)频繁重启。

解决这个问题的关键,在于必须搞清楚 LLM 推理过程中显存到底被哪些组件吃掉了,以及如何通过确定性的指标来驱动 GPU Pod 的弹性伸缩。

2. 算力成本拆解:KV Cache 动态占用与 Token 吞吐的数学账

评估大模型推理算力成本,不能照搬传统 Web 应用的 CPU/RAM 预算逻辑。LLM 显存消耗由三部分硬性组成:模型权重静态显存、上下文 KV Cache 动态显存、以及 CUDA Context 与临时激活值(Activation)。

以 FP16 精度的 70B 模型为例,其静态显存占用是固定的:

$$ Memory_{static} = 70 \times 10^9 \times 2 \text{ Bytes} \approx 140 \text{ GB} $$

若采用 4 卡 Tensor Parallelism(TP=4),每张 A100 占用 35GB 静态显存。剩下 45GB 显存由 PagedAttention 划分为物理 Block 管理。此时,决定单卡最大并发能力的是 KV Cache 的理论极限。假设模型 Layer 数量为 $L=80$,Key/Value 头数为 $H=8$,隐层维度为 $D=128$,最大上下文长度 $S=4096$,则单个 Request 满上下文时的 KV Cache 占用为:

$$ Memory_{KV} = 2 \times L \times H \times D \times S \times 2 \text{ Bytes} = 2 \times 80 \times 8 \times 128 \times 4096 \times 2 \approx 1.34 \text{ GB} $$

这意味着剩余 45GB 显存理论上最多只能同时容纳大约 33 个满上下文请求。如果线上出现突发长文本并发,KV Cache 短时间内填满,推理引擎就不得不将物理 Block 换出到 CPU 内存(Swap-out)或者强行抢占(Preemption)中断请求,导致整体吞吐下降 80% 以上。

成本算账的逻辑显而易见:在未验证前增加 GPU 节点是昂贵的。按单张 A100 每小时 2.5 美元计算,扩容一个 8 卡节点意味着每月增加 1.4 万美元成本。因此,必须将 KV Cache 的实际利用率(vllm:gpu_cache_usage_perc)与请求队列长度(vllm:num_requests_waiting)作为 K8s HPA 的核心 Metric,实现精准伸缩。

3. vLLM 与 K8s HPA 结合的弹性伸缩架构设计

传统的 HPA 基于 CPU 利用率扩容在大模型场景下完全失效。必须引入 Custom Metrics API,将 vLLM 暴露的 Prometheus 业务指标暴露给 K8s 伸缩控制器。

伸缩决策不能采用简单的线性比例算法。如果只凭“显存超过 80%”就扩容,冷启动的 3 分钟窗口期足以让服务明显级联故障。我们设计的弹性架构分为三层:

  1. 入口闸门(Ingress Gate):在 vLLM 前置 Nginx/Envoy 限制最大等待队列。超过安全阈值的请求直接返回 429 降级响应,保护现有推理节点不崩溃。
  2. 指标采集层(Prometheus + Prometheus-Adapter):每 5 秒抓取一次vllm:gpu_cache_usage_percvllm:num_requests_waiting
  3. 阶梯式 HPA 策略:当num_requests_waiting > 5且持续 15 秒时,触发 Pod 数量加倍;当gpu_cache_usage_perc < 30%持续 10 分钟时,才平滑缩容,避免频繁冷启动振荡。

4. 生产级 Prometheus 监控指标提取与 Python 弹性扩缩防线代码

下面的 Python 服务展示了如何安全地作为 K8s Custom Metrics 适配器,获取 vLLM 暴露的指标并实施包含熔断与预热检查的扩缩容防线计算。

import time import requests from typing import Dict, Tuple class LLMInferenceAutoscalerGuard: def __init__( self, vllm_metrics_url: str, max_gpu_cache_threshold: float = 0.85, max_waiting_queue: int = 10, warmup_cooldown_seconds: int = 180 ): self.vllm_metrics_url = vllm_metrics_url self.max_gpu_cache_threshold = max_gpu_cache_threshold self.max_waiting_queue = max_waiting_queue self.warmup_cooldown_seconds = warmup_cooldown_seconds self.last_scale_time = 0.0 def parse_prometheus_metrics(self, raw_text: str) -> Dict[str, float]: metrics = {} for line in raw_text.splitlines(): if line.startswith("#") or not line.strip(): continue parts = line.split() if len(parts) >= 2: key, val = parts[0], parts[1] try: metrics[key] = float(val) except ValueError: continue return metrics def fetch_inference_health(self) -> Tuple[bool, float, int]: try: resp = requests.get(self.vllm_metrics_url, timeout=2.0) if resp.status_code != 200: # 监控端点异常,触发安全降级防御 return False, 1.0, 999 parsed = self.parse_prometheus_metrics(resp.text) cache_usage = parsed.get('vllm:gpu_cache_usage_perc', 0.0) waiting_reqs = int(parsed.get('vllm:num_requests_waiting', 0)) return True, cache_usage, waiting_reqs except Exception as err: # 网络超时或解析故障,必须阻止危险的缩容操作 return False, 1.0, 999 def evaluate_scale_decision(self, current_replicas: int) -> Tuple[str, int]: now = time.time() is_healthy, cache_usage, waiting_reqs = self.fetch_inference_health() if not is_healthy: # 指标异常时保持副本数,拒绝在未验证前缩容 return "HOLD_UNHEALTHY_METRICS", current_replicas # 防频繁冷却震荡检查 if now - self.last_scale_time < self.warmup_cooldown_seconds: return "COOLDOWN_WAITING", current_replicas # 紧急扩容条件:KV Cache 接近红线 或 等待队列堆积 if cache_usage >= self.max_gpu_cache_threshold or waiting_reqs >= self.max_waiting_queue: target_replicas = min(current_replicas * 2, 16) # 单次最多翻倍,上限16 Pod if target_replicas != current_replicas: self.last_scale_time = now return "SCALE_UP_EMERGENCY", target_replicas # 平滑缩容条件:显存占用低于 30% 且无排队 if cache_usage < 0.30 and waiting_reqs == 0: target_replicas = max(current_replicas - 1, 2) # 保持最小2副本保底 if target_replicas != current_replicas: self.last_scale_time = now return "SCALE_DOWN_SMOOTH", target_replicas return "HOLD_STABLE", current_replicas if __name__ == "__main__": guard = LLMInferenceAutoscalerGuard( vllm_metrics_url="http://127.0.0.1:8000/metrics", max_gpu_cache_threshold=0.80, max_waiting_queue=5, warmup_cooldown_seconds=180 ) # 模拟一次检测 action, replicas = guard.evaluate_scale_decision(current_replicas=4) print(f"[Autoscaler Decision] Action: {action}, Target Replicas: {replicas}")

5. 压测回归:从 1200 QPS 到 P99 降至 180ms 的成本效益对比

实施该方案后,我们在 Staging 环境使用 Vegeta 模拟了包含长短文本混合的突发流量(QPS 从 200 短时间内飙升至 1200)。

对比数据非常清晰:在使用传统 CPU HPA 策略时,推理集群在第 40 秒出现大规模 429 拒答,P99 延迟突破 5000ms,整体 GPU 显存频繁引发 vLLM 强行 Swap,实际完成的吞吐仅为 850 tokens/s。

采用基于gpu_cache_usage_perc与等待队列梯度的自定义扩缩容方案后,当等待队列首次突破 5 个请求时,系统立即拦截溢出流量并平滑触发扩容。因为设置了 2 副本的温备基线,流量被有效平摊。最终 P99 延迟稳定在 180ms,无任何节点发生显存 OOM。集群在突发流量退去 10 分钟后顺畅缩容,月度 GPU 算力成本相比固定配额方案降低了 42%。

小结:把结论留给可复现的结果

本文的场景用于说明推理服务的检查顺序,不代表某个环境的既成事故或固定收益。变更前应记录基线、版本与配置,控制流量或样本,并比较尾延迟、错误率和资源占用;未达到预设门槛时,应保留或回退原方案。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/21 14:03:48

用 Docker 运行 tf-summarize:一条命令搞定环境隔离与别名配置

用 Docker 运行 tf-summarize&#xff1a;一条命令搞定环境隔离与别名配置 【免费下载链接】tf-summarize A command-line utility to print the summary of the terraform plan 项目地址: https://gitcode.com/gh_mirrors/tf/tf-summarize tf-summarize 是一个用 Go 编…

作者头像 李华
网站建设 2026/8/21 14:02:58

华为OD机试黑白棋算法解析与实现

1. 项目概述&#xff1a;华为OD机试中的黑白棋棋盘问题 黑白棋&#xff08;又称翻转棋&#xff09;是一种经典的策略性棋盘游戏&#xff0c;在华为OD机试中常作为考察编程能力的题目出现。这类题目通常给定一个NN的棋盘&#xff0c;要求选手编写程序计算棋子的合法移动范围或最…

作者头像 李华
网站建设 2026/8/21 13:59:56

头歌实践教学平台:大数据存储2023(三~四)

三、Hive综合应用案例 — 用户搜索日志分析第1关&#xff1a;2018年点击量最高的10个网站域名任务描述 本关任务&#xff1a;分析2018年点击量最高的10个网站域名。编程要求 在右侧编辑器补充代码&#xff0c;分析出2018年点击量最高的10个网站域名。创建数据库&#xff1a;myd…

作者头像 李华
网站建设 2026/8/21 13:59:31

从单元测试学Unity开发:guid-based-reference测试套件深度解读

从单元测试学Unity开发&#xff1a;guid-based-reference测试套件深度解读 【免费下载链接】guid-based-reference A component for giving Game Objects a GUID and a class to create references to objects in any Scene by GUID 项目地址: https://gitcode.com/gh_mirror…

作者头像 李华
网站建设 2026/8/21 13:47:08

聊聊Oblique生态:Maven/JitPack集成、版本演进与作者开源故事

聊聊Oblique生态&#xff1a;Maven/JitPack集成、版本演进与作者开源故事 【免费下载链接】Oblique With Oblique explore new styles of displaying images 项目地址: https://gitcode.com/gh_mirrors/ob/Oblique Oblique 是一个开源免费的 Android 斜切图片展示库&…

作者头像 李华