文章

Prefix-Aware KV Cache Routing:LLM 推理别再重复算相同前缀

本文系统拆解 Prefix-Aware KV Cache Routing 的生产工程价值,从 prefix caching、KV cache block hash、worker 路由、跨节点缓存复用、租户隔离到 SLO 监控,帮助团队减少重复 prefill、降低 TTFT,并避免缓存热点与安全风险。

为什么 LLM 推理会反复计算相同前缀

在真实 LLM 服务中,很多请求并非完全独立。它们往往共享一大段开头内容:system prompt、安全规则、工具 schema、RAG 模板、长文档开头、Few-shot examples、Agent 固定任务说明,甚至同一个企业客户的固定业务上下文。

如果每次请求都从头 prefill,系统就会重复计算同一批 token 的 key/value 张量。单机推理框架已经可以通过 prefix caching 复用这些 KV cache blocks;但进入多 worker、多节点、多租户部署后,新的问题出现了:请求如果被普通负载均衡随机发到不同 worker,缓存就会被打散。明明前缀一样,却因为路由没感知缓存位置,还是要重新 prefill。

所以,生产级优化的重点不只是”打开 prefix cache”,而是让 router、scheduler、KV cache manager、cache namespace、metrics 一起工作。

一句话理解 Prefix-Aware KV Cache Routing

Prefix-aware KV cache routing 的核心很简单:请求进来后,先判断它的 token prefix 和哪些 worker 上已有缓存最接近,再把请求发给最可能复用 KV cache 的 worker。

User Request
-> Tokenize and hash prefix blocks
-> Query worker cache index
-> Route to best cache-match worker
-> Reuse cached KV blocks
-> Prefill only missing suffix
-> Decode normally

这套机制要解决的不是单个请求能不能快,而是集群级别的重复计算浪费。

核心知识结构

可以把这个主题拆成 6 个模块。

1. Prefix Cache

Prefix cache 复用已经计算过的 KV blocks。它适合大量请求共享相同系统提示词、工具说明、模板或长文档前缀的场景。

2. Block Hash

推理框架通常不会只用整段 prompt 做缓存,而是按 token block 管理。每个 block 可以由父 block hash、当前 block tokens,以及 LoRA ID、多模态输入 hash、cache salt 等额外信息共同确定。

3. Cache-Aware Router

Router 不再只看 worker 当前负载,还要看请求 prefix 和 worker 本地缓存的匹配程度。它要在”缓存命中”和”负载均衡”之间做取舍。

4. Worker Cache Index

每个 worker 需要暴露轻量级缓存索引,告诉 router 自己拥有哪些 prefix blocks。这个索引可以是精确的,也可以是近似的。

5. Tenant Isolation

多租户场景不能让不同客户共享同一缓存命名空间。即使模型输出不变,攻击者也可能通过延迟差异推测某些前缀是否被缓存。

6. SLO Metrics

Prefix-aware routing 不能只看 cache hit rate。还要同时看 TTFT、TPOT、worker hotspot、queue time、cache transfer cost 和 SLO goodput。

为什么普通负载均衡会浪费缓存

普通 L7 负载均衡通常关心这些指标:worker 是否健康、连接数是否过高、请求数是否均衡、延迟是否异常。

这对传统 Web 服务足够,但对 LLM 推理不够。因为 LLM worker 的”状态”不只是负载,还有它已经计算过的 KV cache。

假设 3 个请求共享同一段 8K token 的工具说明:

Request A -> Worker 1,完成 prefill,缓存 prefix
Request B -> Worker 2,重新 prefill
Request C -> Worker 3,重新 prefill

从负载均衡角度看,这很公平;从 LLM 推理角度看,这是浪费。

更合理的做法是让后续请求尽量进入已有相同 prefix cache 的 worker。但这里也不能走极端——如果所有相同前缀请求都被打到同一个 worker,它又会变成热点。所以 prefix-aware routing 的难点是:既要复用缓存,又不能把流量压垮到少数 worker 上

典型执行流程

一个生产级 prefix-aware routing 流程可以这样设计:

1. 请求进入网关
2. Tokenizer 生成 prefix token blocks
3. Router 计算或查询 prefix block hash
4. Cache index 返回各 worker 的最长命中前缀
5. Router 结合 cache match、queue length、GPU memory、SLO 做决策
6. 请求被发送到目标 worker
7. Worker 复用已有 KV blocks,只 prefill 未命中的 suffix
8. Decode 阶段正常生成
9. Metrics 系统记录 cache hit tokens、TTFT、queue time、fallback 和热点情况
10. 如果缓存索引过期,最多造成 cache miss,不应影响输出正确性

这里有一个很重要的设计原则:缓存元数据可以弱一致,但模型输出必须保持正确。也就是说,router 以为某个 worker 有缓存,结果去了之后发现没有,最多是重新 prefill;不能因为错误复用 KV cache 导致输出错乱。

路由策略:不要只追求最长前缀命中

最直觉的策略是:把请求发到拥有最长 prefix match 的 worker。但生产里还要加入更多约束。

1. Cache Match Score

衡量目标 worker 能复用多少 token。可以按命中 block 数、命中 token 数或预计节省 prefill 时间来计算。

2. Worker Load

如果一个 worker 虽然缓存命中高,但 queue 已经很长,继续发过去可能让 TTFT 变差。

3. GPU Memory Pressure

Worker 如果 KV cache 已经接近满载,新请求可能触发 eviction,反而降低后续命中率。

4. Tenant Boundary

不同租户、不同安全域、不同 cache salt 的请求不能只因为 prefix 一样就共享缓存。

5. Transfer Cost

如果支持跨节点 KV cache 传输,要评估传输成本是否低于重新 prefill 成本。短前缀不一定值得传输。

score = (
    cache_hit_tokens * prefill_cost_per_token
    - queue_wait_penalty
    - memory_pressure_penalty
    - transfer_cost
    - hotspot_penalty
)

这个分数不是为了精确建模,而是提醒工程团队:最长缓存命中不一定是最佳路由。

集群缓存有三种架构选择

架构优点缺点
Sticky Routing实现简单,不需要复杂 KV transfer容易热点,worker 重启后缓存收益消失
Shared KV Cache Layer缓存生命周期独立于 worker,便于跨实例复用引入序列化、传输和一致性管理成本
Cache-Aware Routing + On-Demand Transfer更灵活,按需拉取 KV blocks系统复杂度最高,需处理 transfer latency 与失败恢复

Sticky Routing

同一类前缀请求尽量打到固定 worker。优点是实现简单,不需要复杂 KV transfer;缺点是容易热点,worker 重启后缓存收益消失。

Shared KV Cache Layer

通过独立缓存层让多个推理实例共享 KV cache,例如 CPU DRAM、NVMe、远程存储或专门的 KV cache service。优点是缓存生命周期独立于 worker,便于跨实例复用;缺点是会引入序列化、传输和一致性管理成本。

Cache-Aware Routing + On-Demand Transfer

Router 先把请求发到最合适的 worker;如果本地没有完整缓存,再按需从其他位置拉取 KV blocks。优点是更灵活;缺点是系统复杂度最高,需要处理 transfer latency、失败恢复和资源隔离。

安全问题:缓存命中也可能泄露信息

很多人会忽略一个细节:即使 KV cache 不直接暴露给用户,缓存命中造成的延迟差异也可能形成侧信道。

例如攻击者可以构造某个敏感前缀,然后观察 TTFT 是否明显下降,推测该前缀是否已经被其他用户请求过。

生产环境至少要做 4 件事:

1. 按租户、项目或信任组隔离 cache namespace
2. 在 hash 中加入 cache salt
3. 避免低安全 hash 算法导致碰撞风险
4. 对跨租户 cache hit 和异常低 TTFT 做监控

如果业务是企业知识库、代码助手、法律文档、医疗问答或内部 Agent,这个问题不能当成理论风险。

指标体系:不要只看 Cache Hit Rate

Prefix-aware routing 至少要看以下 8 类指标:

指标含义
Prefix Hit Tokens实际命中复用的 token 数,而非命中率
TTFT Deltacache hit 与 cache miss 的首 token 延迟差异
Router Decision Latency路由决策本身的耗时
Hotspot Rate是否存在少数 worker 承载绝大部分流量
Eviction Churn缓存驱逐频率是否过高
Transfer Cost跨节点 KV block 传输耗时与带宽开销
SLO Goodput满足 SLO 的请求吞吐量
Isolation Violation是否存在跨租户缓存命中的异常事件
metrics:
  prefix_hit_tokens_p50: 4096
  prefix_hit_tokens_p95: 16384
  ttft_ms_cache_hit_p95: 420
  ttft_ms_cache_miss_p95: 1380
  router_decision_ms_p95: 12
  hotspot_worker_ratio: 0.08
  kv_transfer_ms_p95: 35
  cache_eviction_churn_per_min: 240
  slo_goodput_rps: 61

常见失败模式

Router 只看缓存,不看负载

这样会把热门 prefix 全打到少数 worker,最后 TTFT 反而变差。

Cache index 更新太频繁

索引过细、更新过频会增加控制面压力。很多场景下,弱一致近似索引就够了。

忽略 tokenizer 和模板版本

同样的文本,如果 tokenizer、chat template、tool schema 顺序不同,token prefix 可能并不一致。

把动态内容放在前面

时间戳、request id、用户私有字段放在 prompt 开头,会破坏前缀复用。

没有租户隔离

多租户共享缓存必须设计 namespace 或 salt,否则可能带来隐私和侧信道风险。

生产落地 Checklist

上线前建议逐项检查:

  • 是否固定 system prompt、工具 schema 和模板顺序
  • 是否把动态变量放在 prompt 后部,避免破坏 prefix
  • 是否按 token block 而不是原始字符串计算缓存匹配
  • Router 是否同时考虑 cache match、queue length、GPU memory 和 SLO
  • 是否有 worker cache index,并允许弱一致导致 cache miss
  • 是否记录 prefix hit tokens,而不只是 hit rate
  • 是否监控 cache hit / miss 的 TTFT 差异
  • 是否有热点检测和流量打散策略
  • 是否评估跨节点 KV transfer 是否值得
  • 是否使用 cache namespace 或 cache salt 做多租户隔离
  • 是否为 tokenizer、chat template、tool schema 变更跑回归测试
  • 是否保留 fallback:缓存不可用时仍能正确重新 prefill

结论

Prefix-aware KV cache routing 的本质,是把 KV cache 从单个 worker 的局部优化,升级为整个推理集群的调度资源。

Prefix cache     -> 负责减少重复 prefill
Router           -> 负责把请求发到最可能复用缓存的位置
Scheduler        -> 负责避免热点和队列放大
Cache namespace  -> 负责隔离租户和安全域
Metrics          -> 负责证明 TTFT 与 goodput 是否真的变好

对工程团队来说,最实用的原则是:不要只问”我的 serving engine 是否支持 prefix caching”,而要问”我的请求是否真的被路由到能复用缓存的 worker”。

当 prompt 结构、block hash、worker 路由、缓存隔离和 SLO 监控形成闭环,prefix cache 才能从一个局部优化,变成稳定降低 LLM 推理成本和延迟的生产能力。

常见问题

Prefix-aware routing 和普通负载均衡有什么区别?
普通负载均衡主要按 worker 负载分发请求;prefix-aware routing 会同时考虑请求前缀与各 worker 已缓存 KV blocks 的匹配程度,尽量把请求发到能复用最多缓存的位置。
Prefix cache 命中一定会提升整体吞吐吗?
不一定。它通常能减少重复 prefill 和 TTFT,但如果路由造成热点、跨节点传输成本太高,或者缓存命中只发生在很短前缀上,整体收益可能被抵消。
多租户环境如何避免 KV cache 泄露?
需要按租户、项目或信任组做 cache namespace 或 cache salt 隔离,并避免使用不安全 hash 算法造成碰撞风险;同时要监控基于延迟差异的缓存探测风险。