1. 背景

PD(prefill-decode)分离是大模型目前的基本结构。最简单的调度器只管负载均衡,另个Prefill节点空闲就用哪个,哪个Decode节点队列短就发哪个,完全不考虑两者之间的网络延迟。

         机架 A                          机架 B
┌─────────────────────┐           ┌─────────────────────┐
│                     │           │                     │
│   Prefill-0 ────────┼─── KV ───┼──► Decode-5         │
│                     │   Cache   │                     │
│   Prefill-1 ────────┼─── KV ───┼──► Decode-6         │
│                     │   Cache   │                     │
│   Prefill-2         │           │      Decode-7       │
│   Prefill-3         │           │      Decode-8       │
│      ...            │           │        ...          │
│                     │           │                     │
└─────────────────────┘           └─────────────────────┘
       发送端                         接收端
    (连续编号 GPU)               (分散编号 GPU)

跨机架传输 = 走Spine层 = 高延迟+占用稀缺的上行带宽。

2. 亲和性调度的核心思想

在调度时优先把同一个请求的Prefill和Decode分配到网络距离近的节点对上,从而减少KV cache传输的跨网络跳数和带宽消耗。

网络距离的几个层次

层次 描述 Kvcache 传输路径
同GPU(极端情况) PD不分离,同一GPU完成 显存内,不走网络
同机器 Prefill和Decode在同一服务器 NvlinK
同机架 同一台Leaf交换机下 1 跳,不经Spine
跨机架 不同Leaf交换机 2-3跳,经过Spine

亲和性调度,就是尽量让请求落在前两个层次,最差也在同机架内完成。

3. 亲和性调度调度策略

前文说的网络距离,特指Prefill节点和Decode节点的距离,这里有两种方法。

策略 固定什么 调度什么 适用场景
Decode优先 先选Decode 就近选Prefill 无前缀缓存复用,新请求为主
Prefill优先 先选有缓存的Prefill 就近选Decode 有大量共享前缀,多轮对话为主

Decode节点有状态,不能随便动,一个请求一旦开始Decode,它的KV Cache就住在那个Decode节点的显存里。后续每生成一个token,都需要访问这份KV Cache.Decode节点一旦确定,整个请求的生命周期都绑定在这个节点上,中途迁移代价极大,需要搬KV Cache。

Prefill节点是无状态的,Prefill只做一件事:读Prompt,算出KV Cache,然后把KV Cache发走,就完成了。它本身不持有任何需要长期保留的状态。一般先根据负载均衡选Decode节点(Decode节点是长期持有状态),再根据Decode节点,就近选Prefill节点(Prefill节点是无状态的,位置灵活)。但有一种情况例外,前缀缓存命中,当请求有共享前缀(比如同一个system prompt,或多轮对话的历史)。如:

请求A:[system prompt]+用户问题1 -> prefill-2算过,KV Cache缓存在Prefill-2
请求B: [system prompt]+用户问题2 -> 如果调度到Prefill-2,可以复用缓存

此时前缀KV Cache在Prefill节点上有缓存,Prefill节点变成了有状态的。此时就需要先根据前缀找到有缓存的Prefill节点(固定Prefill),再就近选择Decode节点。

4. 具体技术实现
4.1 静态分组(最简单)

把集群按机架分成若干组PD组,每个组内同时包含Prefill和Decode节点,请求只在组内调度:

PD 组A(机架1)        PD组2(机架2)
   Prefill-0            Prefill-2
   Prefill-1            Prefill-3
   Decode-0             Decode-2
   Decode-1             Decode-3

优点:实现简单,KV Cache不出机架

缺点:组间负载不均衡时无法互相借用资源

4.2 动态拓扑感知调度

调度器维护一张网络拓扑图,实时知道每个节点挂在哪台Leaf交换机下,做请求分配时将网络路数作为调度代价的一部分:

Score = GPU利用率权重* CPU负载+ 队列长度权重*队列深度 + 网络距离权重* 跳数

优点:全局负载均衡和网络亲和性可以动态均衡

缺点:调度器需要感知网络拓扑,实现复杂

4.3  KV Cache位置感知调度

更进一步,当同一个用户的请求有历史KV Cache(比如多轮对话)时,优先把新请求调度到缓存了上一轮KV Cache的Decode节点附近的Prefill节点,避免KV Cache的二次迁移。Mooncack(Kimi)在这里有一些核心贡献,他们把KV Cache看成一种有位置属性的资源来调度。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐