news 2026/6/9 13:51:26

Kubernetes 驱动的 AI 推理服务弹性调度:从 GPU 分配到请求路由

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kubernetes 驱动的 AI 推理服务弹性调度:从 GPU 分配到请求路由

Kubernetes 驱动的 AI 推理服务弹性调度:从 GPU 分配到请求路由

一、AI 推理的"资源浪费"困境:GPU 空闲 70%,但高峰还是扛不住

AI 推理服务部署到 Kubernetes 后,最常见的资源浪费模式是:白天高峰 GPU 利用率 90%,夜间低谷利用率不到 10%。为了应对高峰,不得不按峰值配置 GPU 资源,导致大量时间 GPU 处于空闲状态。更棘手的是,不同模型的 GPU 需求差异巨大——小模型只需 1 块 T4,大模型需要 4 块 A100,资源碎片化严重。

弹性调度的核心是"按需分配 GPU,动态调整副本数"。HPA 根据 GPU 利用率和请求队列深度自动扩缩容,调度器根据 GPU 需求和节点资源智能匹配,请求路由根据模型负载分发流量。三者协同,让 GPU 利用率从 30% 提升到 70% 以上。

二、弹性调度架构

graph TB subgraph 请求入口 A[API Gateway] --> B[请求路由<br/>按模型+负载分发] end subgraph 弹性伸缩 B --> C[推理 Pod 池<br/>模型A: 2副本<br/>模型B: 1副本] C --> D[GPU 利用率监控] D --> E[HPA 决策<br/>扩/缩/维持] E --> C end subgraph 调度优化 E --> F[GPU 拓扑感知<br/>NVLink亲和性] F --> G[碎片整理<br/>低负载时合并节点] end

请求从 API Gateway 进入,路由器根据模型类型和当前负载分发到对应的推理 Pod。HPA 监控 GPU 利用率和请求队列,动态调整副本数。调度器在分配 GPU 时考虑拓扑(NVLink 亲和性)和碎片(低负载合并节点)。

三、实现

3.1 GPU 感知的 HPA

import subprocess import json from typing import Dict class GPUAwareHPA: """GPU 感知的水平自动扩缩容""" def __init__( self, min_replicas: int = 1, max_replicas: int = 10, target_gpu_util: float = 0.7, target_queue_depth: int = 10, ): self.min_replicas = min_replicas self.max_replicas = max_replicas self.target_gpu_util = target_gpu_util self.target_queue_depth = target_queue_depth def get_gpu_metrics(self) -> Dict[str, dict]: """获取各 Pod 的 GPU 利用率""" # 通过 nvidia-smi 或 DCGM-Exporter 获取指标 try: result = subprocess.run( ['kubectl', 'get', '--raw', '/apis/custom.metrics.k8s.io/v1beta1' '/namespaces/default/pods/*/gpu_utilization'], capture_output=True, text=True, timeout=10, ) metrics = json.loads(result.stdout) return self._parse_gpu_metrics(metrics) except Exception: return {} def decide_replicas( self, current_replicas: int, gpu_util: float, queue_depth: int, ) -> dict: """决策副本数""" # GPU 利用率驱动的扩缩 gpu_ratio = gpu_util / self.target_gpu_util desired_by_gpu = max( self.min_replicas, min(self.max_replicas, int(current_replicas * gpu_ratio)) ) # 队列深度驱动的扩容 if queue_depth > self.target_queue_depth: queue_ratio = queue_depth / self.target_queue_depth desired_by_queue = min( self.max_replicas, current_replicas + int(queue_ratio) ) else: desired_by_queue = current_replicas # 取较大值(优先保证不丢请求) desired = max(desired_by_gpu, desired_by_queue) action = 'maintain' if desired > current_replicas: action = 'scale_up' elif desired < current_replicas: action = 'scale_down' return { 'current': current_replicas, 'desired': desired, 'action': action, 'reason': ( f'GPU利用率={gpu_util:.0%}, ' f'队列深度={queue_depth}' ), } def _parse_gpu_metrics(self, raw: dict) -> Dict[str, dict]: """解析 GPU 指标""" parsed = {} for item in raw.get('items', []): name = item['describedObject']['name'] value = item['value'] parsed[name] = {'gpu_utilization': float(value)} return parsed

3.2 模型感知的请求路由

from dataclasses import dataclass from typing import List, Optional @dataclass class InferenceEndpoint: """推理端点""" model_name: str pod_ip: str gpu_type: str current_load: int max_load: int class ModelAwareRouter: """模型感知的请求路由器""" def __init__(self): self.endpoints: List[InferenceEndpoint] = [] def register(self, endpoint: InferenceEndpoint) -> None: self.endpoints.append(endpoint) def route( self, model_name: str, priority: str = "normal" ) -> Optional[InferenceEndpoint]: """路由请求到最优端点""" # 筛选匹配模型的端点 candidates = [ e for e in self.endpoints if e.model_name == model_name and e.current_load < e.max_load ] if not candidates: return None # 按负载率排序(最少连接优先) candidates.sort( key=lambda e: e.current_load / e.max_load ) # 高优先级请求选负载最低的 if priority == "high": return candidates[0] # 普通请求加权轮询 return self._weighted_select(candidates) def _weighted_select( self, candidates: List[InferenceEndpoint] ) -> InferenceEndpoint: """加权选择(负载越低权重越高)""" import random weights = [ 1 - (c.current_load / c.max_load) for c in candidates ] total = sum(weights) if total == 0: return candidates[0] probs = [w / total for w in weights] return random.choices(candidates, weights=probs, k=1)[0]

3.3 GPU 拓扑感知调度

# GPU 拓扑感知调度的 Pod 模板 apiVersion: apps/v1 kind: Deployment metadata: name: llm-inference spec: template: spec: containers: - name: inference image: llm-server:latest resources: limits: nvidia.com/gpu: 2 requests: nvidia.com/gpu: 2 memory: "16Gi" cpu: "4" # 调度约束:优先分配同一 NVLink 域的 GPU affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: gpu-topology operator: In values: ["nvlink-domain-0"]

四、弹性调度的 Trade-offs 分析

扩容延迟:GPU 推理 Pod 的启动时间约 30-60 秒(模型加载占大头),远长于普通 Pod 的 5-10 秒。高峰来临时,扩容可能来不及。解决方案是预热池——维持 1-2 个空闲 Pod 随时待命,代价是额外的 GPU 成本。

缩容保护:缩容太激进会导致刚缩完又扩回来(振荡)。建议缩容冷却时间 5 分钟,且只缩负载最低的 Pod。GPU 利用率低于 30% 才触发缩容,避免在 40-50% 区间频繁伸缩。

多模型共享 GPU:小模型(<2GB)可以多个共享一块 GPU,通过 MPS(Multi-Process Service)或时间片调度。但共享 GPU 的隔离性差——一个模型 OOM 可能影响同 GPU 的其他模型。建议只对延迟不敏感的批处理任务使用 GPU 共享。

Spot 实例的风险:GPU Spot 实例比按需便宜 60%,但随时可能被回收。推理服务使用 Spot 时,必须有回退机制——Spot 被回收时自动在按需实例上启动新 Pod。配合预热池,可以将中断时间控制在 60 秒以内。

五、总结

AI 推理服务的弹性调度核心是"按需分配 GPU,动态调整副本数"。HPA 根据 GPU 利用率和队列深度自动扩缩容,路由器根据模型和负载分发请求,调度器根据 GPU 拓扑优化分配。三者协同,让 GPU 利用率从 30% 提升到 70% 以上。

落地建议:先实现 GPU 感知的 HPA(基于 DCGM-Exporter 指标),再实现模型感知的请求路由。预热池维持 1-2 个空闲 Pod 应对突发流量。缩容冷却 5 分钟,避免振荡。GPU Spot 实例配合按需回退,降低成本。

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

深入解读NXP Kinetis K22F数据手册:从电气特性到硬件设计实践

1. 项目概述&#xff1a;为什么需要深挖MCU的数据手册&#xff1f;在嵌入式硬件开发中&#xff0c;选型与设计的第一步往往不是打开IDE写代码&#xff0c;而是研读一份动辄上百页的数据手册。对于像NXP Kinetis K22F这样的高性能ARM Cortex-M4微控制器&#xff0c;其数据手册中…

作者头像 李华
网站建设 2026/6/9 13:49:30

UnityExplorer终极指南:免费实时调试Unity游戏的完整教程

UnityExplorer终极指南&#xff1a;免费实时调试Unity游戏的完整教程 【免费下载链接】UnityExplorer An in-game UI for exploring, debugging and modifying IL2CPP and Mono Unity games. 项目地址: https://gitcode.com/gh_mirrors/un/UnityExplorer UnityExplorer是…

作者头像 李华
网站建设 2026/6/9 13:47:45

OBS Studio终极指南:免费开源直播软件完全解析

OBS Studio终极指南&#xff1a;免费开源直播软件完全解析 【免费下载链接】obs-studio OBS Studio - Free and open source software for live streaming and screen recording 项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studio 想要开始直播或录屏却不知…

作者头像 李华
网站建设 2026/6/9 13:47:11

Tailwind-Styled-Component类型定义详解:TypeScript开发完全指南

Tailwind-Styled-Component类型定义详解&#xff1a;TypeScript开发完全指南 【免费下载链接】Tailwind-Styled-Component Create Tailwind CSS React components like styled components with class names on multiple lines and conditional class rendering 项目地址: htt…

作者头像 李华
网站建设 2026/6/9 13:44:37

Kinetis K50时钟与ADC电气特性深度解析与高精度测量设计实战

1. 项目概述&#xff1a;从数据手册到设计实战在嵌入式硬件开发中&#xff0c;数据手册是工程师的“圣经”&#xff0c;但直接从数百页的表格和参数中提炼出设计要点&#xff0c;往往令人望而生畏。特别是对于像Kinetis K50这类集成了复杂时钟系统和高精度ADC的微控制器&#x…

作者头像 李华
网站建设 2026/6/9 13:44:19

WaxPatch在大型项目中的应用:处理复杂依赖与模块化热修复

WaxPatch在大型项目中的应用&#xff1a;处理复杂依赖与模块化热修复 【免费下载链接】WaxPatch Dynamically load a lua script to change the behavior of your iOS application. 项目地址: https://gitcode.com/gh_mirrors/wa/WaxPatch WaxPatch是一款强大的iOS应用热…

作者头像 李华