PD 解耦#

什么是 PD 解耦?为什么需要它?#

大语言模型(LLM)推理包含两个不同的阶段:PrefillDecode。Prefill 阶段计算密集,处理整个输入序列;而 Decode 阶段内存密集,管理用于标记生成的键值(KV)缓存。传统上,这两个阶段在统一的引擎中处理,其中预填充和解码批次的联合调度会引入低效性。为了解决这些挑战,我们在 SGLang 中引入了 Prefill 和 Decoding (PD) 解耦

统一调度的问题#

传统统一引擎将预填充和解码批次一起处理,导致了两个显著问题:

  1. 预填充中断:传入的预填充批次频繁中断正在进行的解码批次,导致标记生成出现显著延迟。

  2. DP 注意力不平衡:在数据并行(DP)注意力机制中,一个 DP 工作器可能处理预填充批次,而另一个同时处理解码批次,导致解码延迟增加。

PD 解耦通过分离这两个阶段,为每个阶段实现定制化优化,解决了这些问题。

有关设计细节,请参阅 链接

目前,我们支持 Mooncake 和 NIXL 作为传输引擎。

PD 解耦模式下的性能分析#

当需要在 PD 解耦模式下分析预填充或解码工作器的性能时,请参阅基准测试和性能分析指南中的 PD 解耦模式下的性能分析 部分。由于 torch profiler 的限制,预填充和解码工作器必须使用专用的命令行选项分别进行分析。

路由器集成#

为了在负载均衡和容错的情况下大规模部署 PD 解耦,SGLang 提供了路由器。路由器可以使用各种路由策略在预填充和解码实例之间分发请求。有关设置带有 PD 解耦的路由器的详细信息,包括配置选项和部署模式,请参阅 SGLang 路由器文档

Mooncake#

要求#

uv pip install mooncake-transfer-engine

用法#

Llama 单节点#

python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.1-8B-Instruct \
  --disaggregation-mode prefill \
  --port 30000 \
  --disaggregation-ib-device mlx5_roce0
python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.1-8B-Instruct \
  --disaggregation-mode decode \
  --port 30001 \
  --base-gpu-id 1 \
  --disaggregation-ib-device mlx5_roce0
python -m sglang_router.launch_router --pd-disaggregation --prefill http://127.0.0.1:30000 --decode http://127.0.0.1:30001 --host 0.0.0.0 --port 8000

DeepSeek 多节点#

# prefill 0
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-ib-device ${device_name} \
  --disaggregation-mode prefill \
  --host ${local_ip} \
  --port 30000 \
  --trust-remote-code \
  --dist-init-addr ${prefill_master_ip}:5000 \
  --nnodes 2 \
  --node-rank 0 \
  --tp-size 16 \
  --dp-size 8 \
  --enable-dp-attention \
  --moe-a2a-backend deepep \
  --mem-fraction-static 0.8
# prefill 1
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-ib-device ${device_name} \
  --disaggregation-mode prefill \
  --host ${local_ip} \
  --port 30000 \
  --trust-remote-code \
  --dist-init-addr ${prefill_master_ip}:5000 \
  --nnodes 2 \
  --node-rank 1 \
  --tp-size 16 \
  --dp-size 8 \
  --enable-dp-attention \
  --moe-a2a-backend deepep \
  --mem-fraction-static 0.8
# decode 0
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-ib-device ${device_name} \
  --disaggregation-mode decode \
  --host ${local_ip} \
  --port 30001 \
  --trust-remote-code \
  --dist-init-addr ${decode_master_ip}:5000 \
  --nnodes 2 \
  --node-rank 0 \
  --tp-size 16 \
  --dp-size 8 \
  --enable-dp-attention \
  --moe-a2a-backend deepep \
  --mem-fraction-static 0.8 \
  --max-running-requests 128
# decode 1
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-ib-device ${device_name} \
  --disaggregation-mode decode \
  --host ${local_ip} \
  --port 30001 \
  --trust-remote-code \
  --dist-init-addr ${decode_master_ip}:5000 \
  --nnodes 2 \
  --node-rank 1 \
  --tp-size 16 \
  --dp-size 8 \
  --enable-dp-attention \
  --moe-a2a-backend deepep \
  --mem-fraction-static 0.8 \
  --max-running-requests 128

高级配置#

Mooncake 的 PD 解耦支持以下环境变量,用于对系统行为进行细粒度控制。

预填充服务器配置#

变量

描述

默认值

SGLANG_DISAGGREGATION_THREAD_POOL_SIZE

控制每个 TP 等级用于 KVCache 传输操作的工作线程总数

动态计算值 int(0.75 * os.cpu_count()) // 8),限制为大于 4 且小于 12,以确保效率并防止线程竞争

SGLANG_DISAGGREGATION_QUEUE_SIZE

设置并行传输队列的数量。来自多个解码实例的 KVCache 传输请求将被分片到这些队列中,以便它们能够共享线程和传输带宽。如果设置为 1,则我们按照 fcfs 策略逐个传输请求

4

SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT

在请求初始化期间接收目标 KV 索引的超时时间(秒)

300

如果可以接受更大的平均 TTFT,您可以 export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600(10 分钟)来放宽超时条件。 请注意,当运行中的解码节点失去连接时,此设置将导致预填充实例花费更长时间清理受影响的内存资源。

解码服务器配置#

变量

描述

默认值

SGLANG_DISAGGREGATION_HEARTBEAT_INTERVAL

向预填充引导服务器发送健康检查请求的间隔时间(秒)

5.0

SGLANG_DISAGGREGATION_HEARTBEAT_MAX_FAILURE

将预填充服务器标记为离线之前的连续心跳失败次数

2

SGLANG_DISAGGREGATION_WAITING_TIMEOUT

在请求初始化后接收 KV 缓存的超时时间(秒)

300

如果可以接受更大的平均 TTFT,您可以 export SGLANG_DISAGGREGATION_WAITING_TIMEOUT=600(10 分钟)来放宽超时条件。

NIXL#

要求#

通过 pip 安装。

pip install nixl

或者从源码构建 - 如果您已经安装了 UCX,可能需要这样做。

git clone https://github.com/ai-dynamo/nixl.git
cd nixl
pip install . --config-settings=setup-args="-Ducx_path=/path/to/ucx"

用法#

Llama 单节点#

python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.1-8B-Instruct \
  --disaggregation-mode prefill \
  --port 30000 \
  --disaggregation-transfer-backend nixl
python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.1-8B-Instruct \
  --disaggregation-mode decode \
  --port 30001 \
  --base-gpu-id 1 \
  --disaggregation-transfer-backend nixl
python -m sglang_router.launch_router --pd-disaggregation --prefill http://127.0.0.1:30000 --decode http://127.0.0.1:30001 --host 0.0.0.0 --port 8000

DeepSeek 多节点#

# prefill 0
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-transfer-backend nixl \
  --disaggregation-mode prefill \
  --host ${local_ip} \
  --port 30000 \
  --trust-remote-code \
  --dist-init-addr ${prefill_master_ip}:5000 \
  --nnodes 2 \
  --node-rank 0 \
  --tp-size 16 \
  --dp-size 8 \
  --enable-dp-attention \
  --moe-a2a-backend deepep \
  --mem-fraction-static 0.8
# prefill 1
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-transfer-backend nixl \
  --disaggregation-mode prefill \
  --host ${local_ip} \
  --port 30000 \
  --trust-remote-code \
  --dist-init-addr ${prefill_master_ip}:5000 \
  --nnodes 2 \
  --node-rank 1 \
  --tp-size 16 \
  --dp-size 8 \
  --enable-dp-attention \
  --moe-a2a-backend deepep \
  --mem-fraction-static 0.8
# decode 0
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-transfer-backend nixl \
  --disaggregation-mode decode \
  --host ${local_ip} \
  --port 30001 \
  --trust-remote-code \
  --dist-init-addr ${decode_master_ip}:5000 \
  --nnodes 2 \
  --node-rank 0 \
  --tp-size 16 \
  --dp-size 8 \
  --enable-dp-attention \
  --moe-a2a-backend deepep \
  --mem-fraction-static 0.8 \
  --max-running-requests 128
# decode 1
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-transfer-backend nixl \
  --disaggregation-mode decode \
  --host ${local_ip} \
  --port 30001 \
  --trust-remote-code \
  --dist-init-addr ${decode_master_ip}:5000 \
  --nnodes 2 \
  --node-rank 1 \
  --tp-size 16 \
  --dp-size 8 \
  --enable-dp-attention \
  --moe-a2a-backend deepep \
  --mem-fraction-static 0.8 \
  --max-running-requests 128

ASCEND#

用法#

mf_adapter(下载链接) 与 ascend 后端一起使用,并设置 ASCEND_MF_STORE_URL

pip install mf_adapter-1.0.0-cp311-cp311-linux_aarch64.whl --force-reinstall
export ASCEND_MF_STORE_URL="tcp://xxx.xx.xxx.xxx:xxxx"

使用 Mooncake 后端,更多细节可以在 Mooncake 部分找到。

export ENABLE_ASCEND_TRANSFER_WITH_MOONCAKE=true

Llama 单节点#

python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.1-8B-Instruct \
  --disaggregation-mode prefill \
  --port 30000 \
  --disaggregation-transfer-backend ascend
python -m sglang.launch_server \
  --model-path meta-llama/Llama-3.1-8B-Instruct \
  --disaggregation-mode decode \
  --port 30001 \
  --base-gpu-id 1 \
  --disaggregation-transfer-backend ascend
python -m sglang_router.launch_router --pd-disaggregation --prefill http://127.0.0.1:30000 --decode http://127.0.0.1:30001 --host 0.0.0.0 --port 8000

DeepSeek 多节点#

# prefill 0
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-transfer-backend ascend \
  --disaggregation-mode prefill \
  --host ${local_ip} \
  --port 30000 \
  --trust-remote-code \
  --dist-init-addr ${prefill_master_ip}:5000 \
  --nnodes 1 \
  --node-rank 0 \
  --tp-size 16
# decode 0
python -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-V3-0324 \
  --disaggregation-transfer-backend ascend \
  --disaggregation-mode decode \
  --host ${local_ip} \
  --port 30001 \
  --trust-remote-code \
  --dist-init-addr ${decode_master_ip}:5000 \
  --nnodes 1 \
  --node-rank 0 \
  --tp-size 16