重要提示:如需以 Markdown 形式查看本页,请在 URL 后追加 `.md`。 完整文档索引见 llms.txt
跳到主要内容
完整文档索引见 llms.txt。 在任意 URL 后追加 `.md` 即可查看该页面的 Markdown 版本。

推理路由

推理路由指的是决定由哪个 worker 处理每个 LLM 请求的过程。在小规模场景下,这个决策可能被隐藏在模型服务进程或简单网关内部。随着部署扩展到许多副本和 GPU,它会成为推理优化中的重要组成部分。

一次路由决策会影响如下事项:

  • 请求是否能够复用现有的 KV 缓存
  • 它是否会被长时间运行的生成任务阻塞
  • 目标 worker 是否还有足够的内存余量
  • 预填充或解码工作是否已经让该 worker 饱和
  • 在流量不均衡的模式下,整体 GPU 池是否仍能保持繁忙

因此,推理路由与 前缀缓存KV 缓存卸载预填充-解码解耦 等概念密切相关。

在平台规模上,路由也是一种经济工具。更好的放置策略不仅能让单个请求更快,还能让 GPU 在异构租户和突发工作负载之间维持更高的有效利用。

为什么推理中的路由是不同的

传统负载均衡器会把后端视为相同的黑盒。请求到来后,任何后端都可以处理它,响应离开后也不会留下多少有用状态。当请求短小、无状态、且成本相近时,这种模式工作良好。

LLM 推理在多个方面打破了这些前提:

  • 请求并不相等。一个 100-token 提示词和一个 100k-token 提示词,在内存和计算占用上完全不同。有些请求在毫秒级完成,而另一些请求可能持续生成 token 数分钟。
  • Worker 会携带状态。在预填充期间,模型会构建可被后续请求复用的 KV 缓存。但这种复用只有在下一个请求到达已经持有对应缓存的 worker 时才会发生。这对于多轮聊天和 agent 工作流尤其重要,因为它们的提示词通常会共享较大的前缀。
  • 预填充和解码会压不同资源。预填充主要受计算限制,而解码通常受内存带宽限制。一个忙于长输出解码的 worker 仍然可能接受新的预填充工作,反之亦然。许多分布式系统会把二者完全拆开,以避免浪费 GPU 周期和内存带宽。详见 预填充-解码解耦
  • 不同工作负载的延迟目标不同。代码补全、聊天应用、agent 和批量推理任务,对延迟的要求各不相同。有些工作负载优先考虑低 TTFT,另一些则更关心吞吐量或总成本。如果把每个 worker 都一视同仁,昂贵且长时间运行的请求就可能干扰对延迟敏感的请求。例如,用户期望即时返回的代码补全请求,可能会排在长时间 agent 生成任务后面。

当路由器看不到这些细节时,它就会开始做出糟糕决策,导致:

  • 错失缓存复用。后续请求可能落到一个没有先前 KV 缓存的 worker 上。这会迫使系统重新计算整个前缀,增加 TTFT。
  • 延迟上升。请求可能排在长时间、以解码为主的生成任务之后,或者失去缓存局部性(也就是发生昂贵的重新计算)。
  • 吞吐量下降。GPU 时间被浪费在重复计算前缀,而不是服务新工作。
  • 负载不均衡。某些 worker 被长时间生成任务压满,而其他 worker 大多处于空闲状态。

对于 LLM 推理来说,仅仅把流量均匀摊开是不够的。更重要的是,路由器应最小化服务成本,并让整个 worker 池保持高效和高响应性。

路由策略

LLM 推理路由器可以使用许多信号来决定请求该发送到哪里。具体信号取决于服务栈,但最有价值的通常来自缓存局部性、worker 负载、内存压力和请求优先级。

轮询路由

轮询路由会按顺序遍历可用 worker,并把请求均匀分发到整个池中。它简单、可预测,也适合作为基线方案。

当请求较短、提示词很少重复、并且每个 worker 处理任意请求的成本都大致相同时,它效果最好。

缺点是,轮询路由对缓存完全无感知。在存在 N 个相同 worker 的情况下,如果没有亲和性机制,一个后续请求落到同一 worker 上的概率只有约 1 / N

对于长提示词、多轮聊天和 agent 工作负载,这通常会导致重复的预填充计算和更高的 TTFT。

随机路由

随机路由会为每个请求随机选择一个 worker。

与轮询类似,它很容易实现,有时也适合测试或基准对比,因为几乎不会引入路由偏差。但它忽略了几乎所有推理特定的运行时信息,包括前缀重叠、活跃解码负载和队列深度。

最低负载路由

最低负载路由会把新请求发送给活跃请求数或连接数最少的 worker。

当请求时长差异显著时,它比轮询更有效。处理多个长生成任务的 worker 自然会接收更少的新流量,而大多空闲的 worker 会收到更多流量。当路由器没有可靠的缓存元数据时,这是合理的回退策略。

不过,最低负载路由仍然对缓存无感知。它可能会选择一个负载较轻但没有任何有用前缀缓存的 worker,而不是选择一个负载适中、却能够跳过大部分预填充的 worker。

直接路由

直接路由会显式指定某个 worker。例如,网关、endpoint picker 或自定义调度器可能已经知道哪个 worker 持有某段对话的 KV 缓存。与其让服务层再做一次路由决策,不如直接把请求转发给该 worker。

NVIDIA Dynamo 通过 routing hints 支持这种模型,用于指定目标 worker。

严格来说,这本身不是一种策略,而是一种执行其他地方已做出决策的方式。

感知 KV 缓存利用率的路由

这种策略会考虑每个 worker 的内存中,已有多少空间被 KV 缓存占用。

这一点很重要,因为长上下文工作负载即使原始 GPU 计算利用率看起来并不高,也可能遭遇内存压力。一个 KV 缓存占用率很高的 worker,可能需要驱逐有价值的缓存 block、拒绝新的长提示词,或者失去批处理效率。继续向该 worker 路由更多请求,可能会进一步恶化延迟和吞吐量。

感知 KV 缓存利用率的路由器可以把新请求引导到仍有足够内存余量的 worker。

感知 KV 缓存利用率的负载均衡器会根据负载把请求路由到不同 worker感知 KV 缓存利用率的负载均衡器会根据负载把请求路由到不同 worker

关键点在于,好的路由器不会只因为某个 worker 拥有正确前缀就选择它。落在已经饱和的 worker 上,即使缓存命中,也可能比落在有足够余量的 worker 上、命中较小缓存还更慢。

开源社区已经在推进相关方案。 Gateway API Inference Extension 项目使用 endpoint picker(EPP)来收集每个 worker 上的 KV 缓存利用率、队列长度和 LoRA adapter 信息,并把请求路由到最优副本。

感知前缀的路由

感知前缀的路由会尝试把请求发送到已经缓存了匹配前缀的 worker。

这之所以重要,是因为前缀缓存只有在请求到达能够复用该缓存状态的 worker 时才有帮助。在单个模型服务进程中,缓存是本地的,因此很容易找到;但在分布式部署中,每个 worker 都有自己的缓存,所以路由器需要某种方式在请求之间维持缓存局部性。

感知前缀缓存的路由器会把请求发送到已经缓存该前缀的 worker感知前缀缓存的路由器会把请求发送到已经缓存该前缀的 worker

不同系统对缓存局部性的估计或跟踪方式不同:

  • 前缀亲和性。使用亲和性机制把具有相似前缀的请求路由到同一 worker。简单实现可能依赖客户端级 session affinity,例如把来自同一客户端 IP 的请求路由到同一后端。这样容易实现,但当某个客户端或前缀变热时,会导致 worker 过载;而且它也会错过不同客户端之间的缓存复用机会。
  • 感知前缀的一致性哈希。路由器对请求前缀的一部分做哈希,让相似提示词落到同一或相邻 worker 上。例如,一个简单策略可能只对提示词的前 N 个 token 或字符做哈希。这个方案对路由元数据要求很少,但效果高度依赖哈希策略质量以及提示词长度分布。
  • 路由器上的近似前缀缓存。让路由器维护所有后端 server 前缀缓存的近似查找缓存。这样可以避免细粒度的缓存上报,但在发生驱逐或重启后,路由器视图可能会过时。
  • 精确的缓存感知路由。worker 会发出 KV 缓存事件或更详细的缓存元数据,使路由器能够维护准确的全局缓存放置视图。例如, llm-d 使用来自 vLLM 和 SGLang 的 KV 缓存事件来跟踪服务 Pod 之间的缓存 block 位置。随后调度器会根据传入请求的前缀已有多少部分在该处可用,对各个 worker 打分。它还会把缓存局部性与负载感知信号结合起来,以避免热点副本过载。

一般来说,更准确的缓存信号会提升缓存复用并减少重复预填充工作。代价则是更高的协调成本、更多元数据交换,以及路由层更重的工作。

感知预填充/解码的路由

当预填充和解码被拆分到不同 worker 上时,路由会变得更有意思。在解耦设置中,路由器可能需要决定:

  • 请求应使用本地预填充,还是独立的预填充 worker
  • 哪个解码 worker 应持有当前活跃生成
  • KV 缓存应如何在预填充 worker 和解码 worker 之间迁移
  • 缓存局部性是否值得承担传输成本

对于短提示词,本地预填充可能更快,因为它避免了在 worker 之间迁移 KV 缓存。对于具有高缓存重叠的长提示词,路由到能够复用已有缓存的 worker 可能更重要。路由策略必须同时考虑计算成本与数据移动成本。

这也是为什么推理路由不只是网络层问题。它需要来自模型运行时、调度器和缓存管理器的信息。

混合评分

一些推理路由器会演化成多信号评分系统。它们会结合多个因素,来估计每个 worker 上的服务成本。

  • 前缀与 KV 缓存命中概率。该 worker 是否已经包含请求前缀某一部分的 KV 缓存?
  • KV 缓存内存利用率。GPU 内存中有多少已经被活跃或已缓存的 KV 状态占用?该 worker 是否接近驱逐压力?
  • 队列长度。还有多少请求在等待?
  • 活跃 token 数与解码负载。当前有多少 token 正在生成?这通常是解码阶段内存带宽压力的良好代理指标。
  • LoRA adapter 可用性。该 worker 是否已经加载了正确的 adapter?在执行过程中切换 adapter 的成本很高。
  • 预填充与解码角色。在解耦设置下,这个 worker 是否专用于预填充或解码?
  • SLA 或优先级类别。该请求是否有严格的延迟要求,或者更高的调度优先级?

多个开源项目已经在朝这个方向发展:

  • The SGLang router 使用带有负载均衡回退的缓存感知路由启发式。它借助 radix trees 和队列计数来跟踪近似前缀局部性,然后根据系统失衡程度,在缓存感知路由和最短队列路由之间切换。
  • Dynamo 通过估计各 worker 上的预填充与解码成本来路由请求。它会考虑 KV 缓存重叠、活跃解码 block 和工作负载放置,以减少冗余计算并提升服务效率。
  • llm-dGateway API Inference Extension 项目之上构建推理调度。它结合缓存局部性、worker 负载和其他运行时信号,在 Kubernetes 上提供智能的请求路由与调度。

常见问题

推理路由和负载均衡是一回事吗?

推理路由包含负载均衡,但范围更广。普通负载均衡器主要是在后端之间分摊流量;推理路由器还会考虑缓存局部性、KV 缓存内存压力、adapter 状态、预填充成本、解码负载,以及请求优先级和 SLA。

感知缓存的路由一定会降低延迟吗?

不一定。命中一个负载过高 worker 上的缓存,可能比命中一个轻载 worker 上较小的缓存更慢。好的路由器会把缓存重叠和队列、容量信号结合起来,而不是只为了缓存命中率做优化。

每个自托管 LLM 部署都应该使用感知缓存的路由吗?

不一定。如果流量较低、提示词较短,或者缓存复用很少,可以先从简单路由开始。当重复上下文和分布式 worker 让重新计算代价变高时,再加入感知缓存的路由。