
KEDA 驱动的 LLM 弹性伸缩基于自适应等待队列的实战演练在前面的文章中我们深入分析了为什么传统的基于 CPU / 内存利用率的 Kubernetes HPA 无法胜任大模型LLM推理服务的弹性伸缩。大模型推理引擎如 vLLM、TGI、TensorRT-LLM在启动时就会独占预分配绝大部分显存且在生成阶段 CPU 负载极低导致通用监控指标完全失真。为了让大模型服务具备感知真实业务压力的伸缩能力业界最推崇的解决方案是引入KEDAKubernetes Event-driven Autoscaling基于事件驱动的自动伸缩器。KEDA 允许我们直接将 Prometheus、Kafka、Redis 等外部数据源的实时业务指标作为伸缩触发器Triggers。本文将带大家通过一个完整的生产实战演示如何使用 KEDA 采集 vLLM 的内部等待队列深度Waiting Queue Size与KV Cache 显存饱和度构建一套反应敏锐、扩容果断、缩容平稳的自适应弹性体系。flowchart LR vLLMPod[vLLM 推理服务: 暴露 /metrics 接口] --|抓取 num_requests_waiting| Prometheus[Prometheus 监控服务] Prometheus --|秒级指标聚合查询| KEDAOperator[KEDA Operator 控制器] KEDAOperator --|计算扩缩容副本期望| ScaledObject[ScaledObject 自定义资源] ScaledObject --|驱动底层 HPA| K8sHPA[Kubernetes 原生 HPA] K8sHPA --|快速扩容 GPU 副本| LLMDeployment[vLLM Deployment 副本池]1. 核心伸缩指标的数学建模在配置 KEDA 伸缩策略前我们必须明确伸缩算法的决策逻辑第一优先级指标等待队列深度vllm:num_requests_waiting只要任何一个实例的内部等待队列中有待处理请求队列长度 $ 0$说明当前集群的算力已经无法做到“随到随算”必须立即触发扩容目标阈值设为targetValue: 2平均每个实例排队超过 2 个请求即扩容。第二优先级指标GPU KV Cache 使用率vllm:gpu_cache_usage_factor当没有请求排队但所有实例的显存 KV Cache 占用率普遍超过 80% 时说明系统已逼近饱和临界点应提前触发温和扩容防患于未然目标阈值设为targetAverageValue: 0.75。2. KEDA ScaledObject 生产级配置清单在 Kubernetes 集群中部署好 KEDA 后我们为推理服务创建如下的ScaledObject资源apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: vllm-llama3-autoscaler namespace: ai-serving spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: vllm-llama3-70b minReplicaCount: 2 # 保留最小常驻保底副本避免全量冷启动 maxReplicaCount: 16 # 限制最大物理卡上限防止账单失控 pollingInterval: 5 # 每 5 秒极速轮询一次 Prometheus 指标 cooldownPeriod: 300 # 冷却时间 300 秒防止频繁缩容抖动 advanced: horizontalPodAutoscalerConfig: behavior: scaleUp: stabilizationWindowSeconds: 0 # 扩容零等待立即执行 policies: - type: Percent value: 100 # 突发流量时允许副本数瞬间翻倍 periodSeconds: 15 scaleDown: stabilizationWindowSeconds: 300 # 缩容需平稳观察 5 分钟 policies: - type: Pods value: 1 # 每次仅缩容 1 个 Pod缓慢收敛 periodSeconds: 60 triggers: # 触发器 1: 监控排队积压请求数 - type: prometheus metadata: serverAddress: http://prometheus-k8s.monitoring.svc:9090 metricName: vllm_waiting_requests_sum query: sum(vllm:num_requests_waiting{namespaceai-serving, servicevllm-llama3-70b}) threshold: 2 # 触发器 2: 监控平均 KV Cache 显存饱和度 - type: prometheus metadata: serverAddress: http://prometheus-k8s.monitoring.svc:9090 metricName: vllm_gpu_cache_usage_avg query: avg(vllm:gpu_cache_usage_factor{namespaceai-serving, servicevllm-llama3-70b}) threshold: 0.753. 应对冷启动配合 Cluster Autoscaler 与预热节点池KEDA 计算出需要扩容 Pod 后如果集群内没有足够的空闲 GPU 物理机器Pod 会陷入 Pending 状态。为了实现端到端的快速交付我们必须配置两级协同package main import ( context fmt time ) // AutoScalePrewarmCoordinator 负责在大促前夕或感知到流量爬坡趋势时提前向云厂商申请 GPU 节点 type AutoScalePrewarmCoordinator struct { MinStandbyNodes int } func (c *AutoScalePrewarmCoordinator) EvaluateClusterCapacity(ctx context.Context, totalWaitingRequests int) { fmt.Printf([AUTOSCALE CHECK] 当前总排队请求数: %d\n, totalWaitingRequests) // 当总排队数陡增超过 10 笔时立即通知节点池拉起备用物理机 if totalWaitingRequests 10 { fmt.Println([CLUSTER WARN] 触发物理 GPU 节点池紧急预热提前申请 2 台 8*H100 宿主机) } } func main() { coordinator : AutoScalePrewarmCoordinator{MinStandbyNodes: 2} coordinator.EvaluateClusterCapacity(context.Background(), 14) }4. 生产避坑准则Prometheus 采集频率必须对齐KEDA 的pollingInterval: 5要求 Prometheus 对 vLLM/metrics接口的抓取间隔scrape_interval也必须配置为5s。如果 Prometheus 每 30 秒才抓取一次KEDA 会因为读取到陈旧指标而产生阶梯状的扩容滞后。严格配置缩容冷却Cooldown Window大模型的请求具有明显的突发性与长文本延续性。一个请求结束后可能在 10 秒后又产生多轮追问。如果缩容太快Pod 刚被销毁就又被迫重新拉起会在频繁的“冷启动加载权重 - 销毁”中把集群拖垮。生产环境务必保持 300 秒以上的缩容平稳窗口。