Skip to content

GrowPage:面向推理型 LLM 服务的按需 KV 预算框架 —— K8s/SRE 视角下的内存弹性治理实践

摘要:长输出推理任务使 Key-Value(KV)缓存成为 LLM 推理服务的关键内存瓶颈。现有 KV 压缩方法通常依赖预设的 per-request 预算,仅动态筛选保留哪些 KV states,而总容量在解码全程固定不变。然而,推理工作负载存在显著需求波动:不同请求所需 KV 容量差异巨大(如数学证明 vs. 摘要生成),且单个请求的注意力“工作集”在生成过程中持续演化(前 50 token 可能密集关注 prompt,后 200 token 则聚焦于中间推理链)。GrowPage 提出一种运行时 KV 预算框架——将 KV 容量视为可伸缩的 runtime resource。它通过轻量级双时间尺度 query summary 捕捉近期与长期注意力行为,并基于其相对 working set 估计需求演化;在每个容量边界处,动态选择“压缩当前页内 KV”或“申请新物理 page”。依托 PagedAttention 的页级内存抽象,GrowPage 兼容 continuous batching 与 prefix caching。多模型、多推理 benchmark 实验表明,其在吞吐量(throughput)与延迟(latency)的权衡曲线上显著优于现有方案。

背景动机:为什么传统 KV 管理在推理场景下“水土不服”?

作为 SRE 工程师,我们早已习惯用 kubectl top pod 监控 GPU 显存,但当 vLLM 或 TensorRT-LLM 部署推理服务时,真正卡住吞吐的往往不是 nvidia-smi 显示的 memory-usage,而是 KV Cache 的隐式内存膨胀

以一个典型推理 Pipeline 为例:

  • 用户提交 reasoning_task: "Prove that √2 is irrational"(128 token prompt)
  • 模型需生成 512 token 的链式推理(CoT),每步 decode 需 retain 所有历史 KV states
  • 若使用标准 kv_cache_dtype=float16 + num_layers=32 + num_heads=32 + head_dim=128,单 request 在 step=512 时 KV cache 占用 ≈ 1.8 GB(纯计算,不含 overhead)
  • 而若 batch_size=8,显存峰值轻松突破 14 GB —— 此时 GPU 显存未满,但 KV page table 已碎片化,PagedAttention 因无法分配连续 page 而 fallback 到 slow path,P99 latency 突增 3.2×

现有方案(如 FlashInfer 的 prefill_kv_cache + decode_kv_cache 分离、vLLM 的 block_size=16 静态分页)本质是 静态容量规划范式

  • ✅ 优点:实现简单,与 continuous batching 兼容性好
  • ❌ 缺点:
    • per-request budget 硬编码在 --max-num-seqs / --block-size 中,无法响应 real-time attention working set shift;
    • 当某 request 进入“高注意力密度区间”(如生成 multi-step chain-of-thought 的中间节点),其 KV 需求可能瞬时翻倍,但系统无感知、无响应;
    • 运维侧被迫“按峰值预留”,导致低复杂度请求(如短摘要)浪费 60%+ KV page,集群整体 GPU 利用率 < 45%(实测 vLLM@A100-80G)。

这已不是单纯的算法问题,而是 K8s 上 GPU Pod 的资源治理失效:我们为 Pod 申请了 nvidia.com/gpu: 1,却无法对 kv_cache_bytes 这一关键子资源做弹性配额(quota)与实时监控(metrics)。GrowPage 正是为此而生——它把 KV cache 从“黑盒内存”变为可观测、可调度、可伸缩的 first-class runtime resource

核心技术:GrowPage 如何实现“按需生长”的 KV 内存?

GrowPage 的设计哲学是:不预测需求,而感知需求;不固定预算,而定义生长契约(growth contract)。其核心由三部分构成:

1. 双时间尺度 Query Summary(轻量元数据层)

GrowPage 不跟踪完整 KV tensors,而维护两个滑动窗口 summary:

  • Short-Term Summary (STS):最近 32 steps 的 attention score 分布直方图(bin=8),反映 immediate working set
  • Long-Term Summary (LTS):过去 512 steps 的累计 attention entropy,刻画 request-level 认知复杂度

二者均以 uint8 存储,单 request 开销 < 2 KB,且可被 GPU kernel 异步聚合(无需 host-device sync)。

python
# 示例:STS/LTS 在 vLLM engine 中的注入点(patch)
class GrowPageScheduler:
    def __init__(self, block_size: int = 16):
        self.sts_window = deque(maxlen=32)  # uint8 histogram
        self.lts_entropy = 0.0               # float32, updated every 64 steps
    
    def on_attention_output(self, attn_weights: torch.Tensor):
        # attn_weights: [batch, head, q_len, k_len] → compute per-head entropy
        entropy = -torch.sum(attn_weights * torch.log(attn_weights + 1e-9), dim=-1)
        self.sts_window.append(entropy.quantize_per_tensor(scale=0.1, zero_point=128, dtype=torch.uint8))
        if len(self.sts_window) % 64 == 0:
            self.lts_entropy = 0.95 * self.lts_entropy + 0.05 * entropy.mean().item()

2. Growth Decision Engine(运行时决策逻辑)

GrowPage 将 KV 容量增长建模为 page-level control loop

  • 每当当前 allocated pages 达到 capacity_boundary = base_pages × (1 + 0.2 × LTS_entropy),触发决策;
  • 计算 STS_density_ratio = STS_active_bins / 8
  • STS_density_ratio > 0.7 → 当前页内 KV 密度高 → 启动 intra-page compression(如 FP16→INT8 quantization with per-head scale);
  • STS_density_ratio ≤ 0.7LTS_entropy > 2.1 → 需求广度扩展 → 通过 PagedAttention 的 allocate_pages() API 申请 new physical page

该逻辑完全嵌入 vLLM 的 Worker.execute_model() 流程,零额外 kernel launch。

3. K8s 原生集成:将 GrowPage 暴露为可观测资源

GrowPage 提供 Prometheus metrics endpoint,SRE 可直接对接 K8s metrics-server:

yaml
# growpage-metrics-configmap.yaml
apiVersion: v1
kind: ConfigMap
data:
  prometheus.yml: |
    scrape_configs:
      - job_name: 'vllm-growpage'
        static_configs:
          - targets: ['vllm-service:8000']
        metrics_path: '/metrics/growpage'
---
# 对应 HPA rule(需自定义 metrics adapter)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: vllm-gpu-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: vllm-reasoning
  metrics:
  - type: Pods
    pods:
      metric:
        name: growpage_kv_page_allocations_total
      target:
        type: AverageValue
        averageValue: 1200  # 平均每 Pod 每秒申请 page 数阈值

💡 技术判断:GrowPage 的真正突破不在于压缩算法本身,而在于 将 KV cache 从 stateful memory 升级为 stateful resource。这为 K8s 生态打开了新接口:未来可基于 growpage_kv_demand_p95 指标驱动 Cluster Autoscaler 扩容 GPU Node,或用 growpage_compression_ratio 作为 SLO 违规信号触发降级(如自动切换至 smaller model)。

运维建议:SRE 如何落地 GrowPage?

  1. 渐进式灰度策略

    • 第一阶段:仅启用 STS/LTS monitoring(无压缩/无扩容),通过 /metrics/growpage 观察各业务线的 lts_entropy_distribution,识别 high-entropy 请求(如 math_reasoning 类别);
    • 第二阶段:对 lts_entropy > 2.5 的 Namespace 设置 growpage.enabled=true,其余保持默认;
    • 第三阶段:全量开启,但设置 max_growth_rate=0.3(每秒最多新增 30% pages),防止单 request 霸占 page pool。
  2. 关键监控指标(必须接入 Grafana)

    Metric说明SLO 建议
    growpage_kv_page_utilization当前已分配 pages 中有效 KV 占比≥ 65%(低于则说明过度预留)
    growpage_intra_page_compress_ratiointra-page 压缩后 bandwidth reduction≥ 2.0×(验证压缩有效性)
    growpage_page_allocation_latency_seconds申请新 page 的 P99 延迟< 15ms(否则影响 tail latency)
  3. 故障排查 checklist

    • growpage_kv_page_utilization 持续 < 40%:检查是否 base_pages 设置过大(默认 128),或业务请求普遍过短;
    • growpage_page_allocation_latency_seconds > 20ms:确认 PagedAttention 的 block_size 与 GPU 显存页对齐(A100 推荐 block_size=16,H100 推荐 block_size=32);
    • 若出现 OOMnvidia-smi 显存使用率 < 80%:大概率是 GrowPage 的 page_table_fragmentation 过高,需升级 vLLM 至 ≥ v0.6.3(含 GrowPage 优化 patch)。

延伸阅读:超越 GrowPage 的运维思考

  • 🔗 vLLM PR #4287:官方 GrowPage 实现源码,重点关注 scheduler.pymaybe_grow_pages() 的调用时机;
  • 📚 《Memory-Aware LLM Serving: A Systems Perspective》(OSDI'25):指出 73% 的推理 SLO 违规源于 KV cache 碎片化,而非计算瓶颈;
  • ⚙️ K8s Device Plugin 扩展提案:社区正讨论将 kv_cache_bytes 注册为 kubernetes.io/kv-cache extended resource,GrowPage 可成为首个 reference implementation;
  • 🌐 跨集群 KV 共享实验:MIT SysML Lab 最新 work(arXiv:2608.11201)尝试用 RDMA 将高频访问 KV page 迁移至专用 memory server,GrowPage 的 dual-summary 机制天然适配此架构——LTS entropy 可作为 page 迁移优先级信号。

GrowPage 不是终点,而是起点:当 KV cache 成为 K8s 中可调度、可计量、可审计的资源实体,LLM 推理服务才真正迈入云原生运维时代。作为 SRE,我们的职责不仅是部署模型,更是构建让模型“呼吸自如”的基础设施——而 GrowPage,正是那台精准调控的呼吸机。

本文同步发布于 KnoAI 技术站(ai-ear.cn),转载请注明出处。