跳转至

动态分块流水线并行(DeepSeek-V3.1)

快速开始

vLLM-Ascend 支持动态分块流水线并行(CPP),用于优化流水线并行场景下的预填充性能。该功能从版本 v0.19.1rc1 开始支持。

Important

CPP 专为在 Prefill-Decode(PD)分离部署中的 P(Prefiller)节点上使用而设计。 D(Decoder)节点无需配置 CPP。CPP 基于 profiling 数据动态计算最优分块大小,可显著降低 P 节点上长序列的首 Token 时间(TTFT)。

本指南演示在 3 台 Atlas 800T A3 服务器(64GB × 16)上使用 DeepSeek-V3.1 进行 PD 分离部署:一台服务器作为 Prefiller(P 节点,启用 CPP),两台服务器作为 Decoder(D 节点,不启用 CPP,采用 DP32 标准配置)。

有关配置详情,请参阅功能指南。

有关设计详情,请参阅设计文档。

有关完整的 PD 分离部署说明(环境验证、Mooncake 安装、代理部署),请参阅:

环境准备

模型权重

  • DeepSeek-V3.1-W8A8(量化版本):1 个 Atlas 800T A3(64GB × 16)节点

下载到共享目录,例如 /mnt/weight/

使用 Docker 运行

在每个节点上启动一个 Docker 容器。

export IMAGE=m.daocloud.io/quay.io/ascend/vllm-ascend:v0.23.0
export NAME=vllm-ascend

docker run --rm \
--name $NAME \
--net=host \
--shm-size=1g \
--device /dev/davinci0 \
--device /dev/davinci1 \
--device /dev/davinci2 \
--device /dev/davinci3 \
--device /dev/davinci4 \
--device /dev/davinci5 \
--device /dev/davinci6 \
--device /dev/davinci7 \
--device /dev/davinci8 \
--device /dev/davinci9 \
--device /dev/davinci10 \
--device /dev/davinci11 \
--device /dev/davinci12 \
--device /dev/davinci13 \
--device /dev/davinci14 \
--device /dev/davinci15 \
--device /dev/davinci_manager \
--device /dev/devmm_svm \
--device /dev/hisi_hdc \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/Ascend/driver/tools/hccn_tool:/usr/local/Ascend/driver/tools/hccn_tool \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /etc/hccn.conf:/etc/hccn.conf \
-v /mnt/weight:/mnt/weight \
-it $IMAGE bash

安装 Mooncake

PD 分离的 KV 缓存传输需要 Mooncake。有关安装和编译步骤,请参阅PD 分离多节点 - 安装 Mooncake。

部署

Important

在 PD 分离部署中,仅在 P(Prefiller)节点上启用 CPP。D(Decoder)节点不使用流水线并行运行,专注于低延迟的逐 Token 解码。

  • 建议使用 MooncakeConnectorV1 作为 kv_connector,因为它对 PP 提供更全面的支持。
  • 建议不要在 PP 的 P 节点上启用 async-scheduling,因为这可能导致预填充阶段性能下降。

假设 P 服务器 IP 为 192.0.0.1,D 服务器 IP 为 192.0.0.3(解码器 1)和 192.0.0.4(解码器 2)。

#!/bin/sh
unset https_proxy
unset http_proxy

# For nic_name, run the `ifconfig` command to check the network adapter whose IP address is the same as that of the local host.
nic_name="eth0"
local_ip="192.0.0.1"
export HCCL_IF_IP=$local_ip
export GLOO_SOCKET_IFNAME=$nic_name
export TP_SOCKET_IFNAME=$nic_name
export HCCL_SOCKET_IFNAME=$nic_name

export OMP_PROC_BIND=false
export PYTORCH_NPU_ALLOC_CONF="expandable_segments:True"
export OMP_NUM_THREADS=1
export HCCL_BUFFSIZE=2048
export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
export HCCL_OP_EXPANSION_MODE="AIV"
export VLLM_USE_V1=1
export TASK_QUEUE_ENABLE=1
export ASCEND_LAUNCH_BLOCKING=0
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1
export VLLM_RPC_TIMEOUT=3600000
export VLLM_EXECUTE_MODEL_TIMEOUT_SECONDS=30000
export HCCL_EXEC_TIMEOUT=204
export HCCL_CONNECT_TIMEOUT=120

vllm serve /mnt/weight/DeepSeek-V3.1-w8a8 \
  --host 0.0.0.0 \
  --port 8003 \
  --served-model-name model \
  --tensor-parallel-size 8 \
  --pipeline-parallel-size 2 \
  --enable-expert-parallel \
  --max-num-seqs 32 \
  --max-model-len 131072 \
  --max-num-batched-tokens 32768 \
  --gpu-memory-utilization 0.9 \
  --enable-chunked-prefill \
  --enable-prefix-caching \
  --no-async-scheduling \
  --trust-remote-code \
  --quantization ascend \
  --additional-config '{
    "scheduler_config": {
      "profiling_chunk_config": {"enabled":true, "smooth_factor":1.0, "min_chunk":4096}
    }
  }' \
  --kv-transfer-config \
  '{
    "kv_connector": "MooncakeConnectorV1",
    "kv_role": "kv_producer",
    "kv_port": "36000",
    "engine_id": "0",
    "kv_connector_extra_config": {
      "prefill": {
        "pp_size": 2,
        "dp_size": 1,
        "tp_size": 8
      },
      "decode": {
        "dp_size": 32,
        "tp_size": 1
      }
    }
  }'

如果日志输出 vLLM API server started on 0.0.0.0:8003,则表示服务器已成功启动。

D 节点使用 launch_online_dp.py 在每个节点上启动多个 DP 实例。从仓库中获取启动器和模板脚本:

  • launch_online_dp.py

    在每个 D 节点上修改 run_dp_template.sh。启动器会向模板传递七个位置参数($1–$7)。有关每个参数的完整说明,请参阅 PD 分离多节点。

    #!/bin/sh
    unset https_proxy
    unset http_proxy
    
    nic_name="eth0"  # network card name
    local_ip="192.0.0.3"
    export HCCL_IF_IP=$local_ip
    export GLOO_SOCKET_IFNAME=$nic_name
    export TP_SOCKET_IFNAME=$nic_name
    export HCCL_SOCKET_IFNAME=$nic_name
    export OMP_PROC_BIND=false
    export OMP_NUM_THREADS=10
    export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
    export HCCL_BUFFSIZE=600
    export TASK_QUEUE_ENABLE=1
    export HCCL_OP_EXPANSION_MODE="AIV"
    export VLLM_USE_V1=1
    export ASCEND_RT_VISIBLE_DEVICES=$1
    vllm serve /mnt/weight/DeepSeek-V3.1-w8a8 \
      --host 0.0.0.0 \
      --port $2 \
      --data-parallel-size $3 \
      --data-parallel-rank $4 \
      --data-parallel-address $5 \
      --data-parallel-rpc-port $6 \
      --tensor-parallel-size $7 \
      --enable-expert-parallel \
      --seed 1024 \
      --served-model-name model \
      --max-model-len 131072 \
      --max-num-batched-tokens 256 \
      --max-num-seqs 40 \
      --trust-remote-code \
      --gpu-memory-utilization 0.94 \
      --quantization ascend \
      --no-enable-prefix-caching \
      --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
      --additional-config '{
        "scheduler_config": {"recompute_scheduler_enable": true},
        "multistream_overlap_shared_expert": true,
        "finegrained_tp_config": {"lmhead_tensor_parallel_size": 16}
      }' \
      --kv-transfer-config \
      '{
        "kv_connector": "MooncakeConnectorV1",
        "kv_role": "kv_consumer",
        "kv_port": "36000",
        "engine_id": "0",
        "kv_connector_extra_config": {
          "prefill": {
            "pp_size": 2,
            "dp_size": 1,
            "tp_size": 8
          },
          "decode": {
            "dp_size": 32,
            "tp_size": 1
          }
        }
      }'
    
    #!/bin/sh
    unset https_proxy
    unset http_proxy
    
    nic_name="eth0"  # network card name
    local_ip="192.0.0.4"
    export HCCL_IF_IP=$local_ip
    export GLOO_SOCKET_IFNAME=$nic_name
    export TP_SOCKET_IFNAME=$nic_name
    export HCCL_SOCKET_IFNAME=$nic_name
    export OMP_PROC_BIND=false
    export OMP_NUM_THREADS=10
    export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
    export HCCL_BUFFSIZE=600
    export TASK_QUEUE_ENABLE=1
    export HCCL_OP_EXPANSION_MODE="AIV"
    export VLLM_USE_V1=1
    export ASCEND_RT_VISIBLE_DEVICES=$1
    vllm serve /mnt/weight/DeepSeek-V3.1-w8a8 \
      --host 0.0.0.0 \
      --port $2 \
      --data-parallel-size $3 \
      --data-parallel-rank $4 \
      --data-parallel-address $5 \
      --data-parallel-rpc-port $6 \
      --tensor-parallel-size $7 \
      --enable-expert-parallel \
      --seed 1024 \
      --served-model-name model \
      --max-model-len 131072 \
      --max-num-batched-tokens 256 \
      --max-num-seqs 40 \
      --trust-remote-code \
      --gpu-memory-utilization 0.94 \
      --quantization ascend \
      --no-enable-prefix-caching \
      --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
      --additional-config '{
        "scheduler_config": {"recompute_scheduler_enable": true},
        "multistream_overlap_shared_expert": true,
        "finegrained_tp_config": {"lmhead_tensor_parallel_size": 16}
      }' \
      --kv-transfer-config \
      '{
        "kv_connector": "MooncakeConnectorV1",
        "kv_role": "kv_consumer",
        "kv_port": "36000",
        "engine_id": "0",
        "kv_connector_extra_config": {
          "prefill": {
            "pp_size": 2,
            "dp_size": 1,
            "tp_size": 8
          },
          "decode": {
            "dp_size": 32,
            "tp_size": 1
          }
        }
      }'
    

    在每个 D 节点上启动服务:

    # on 192.0.0.3 (decoder 1, DP rank 0–15)
    python launch_online_dp.py --dp-size 32 --tp-size 1 --dp-size-local 16 --dp-rank-start 0 --dp-address 192.0.0.3 --dp-rpc-port 12321 --vllm-start-port 7100
    # on 192.0.0.4 (decoder 2, DP rank 16–31)
    python launch_online_dp.py --dp-size 32 --tp-size 1 --dp-size-local 16 --dp-rank-start 16 --dp-address 192.0.0.3 --dp-rpc-port 12321 --vllm-start-port 7100
    

在与 prefiller 服务实例相同的节点上运行一个代理服务器。您可以在仓库的 examples 目录中获取代理程序:load_balance_proxy_server_example.py

python load_balance_proxy_server_example.py \
    --host 192.0.0.1 \
    --port 8080 \
    --prefiller-hosts 192.0.0.1 \
    --prefiller-port 8003 \
    --decoder-hosts \
      192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 \
      192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 192.0.0.3 \
      192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 \
      192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 192.0.0.4 \
    --decoder-ports \
      7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 \
      7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115
参数 含义
--port 代理端口
--prefiller-port 所有 prefill 端口
--decoder-ports 所有 decoder 端口

使用代理服务器端点检查服务健康状态。

curl http://192.0.0.1:8080/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "model",
        "messages": [
            {
                "role": "system",
                "content": "You are a useful AI assistant."
            },
            {
                "role": "user",
                "content": "Question: Janet'\''s ducks lay 16 eggs per day. She eats three for breakfast and bakes muffins with four. She sells the remainder for $2 each. How much does she make?\nAnswer:"
            }
        ],
        "max_completion_tokens": 100,
        "temperature": 0
    }'

要验证 CPP 是否在 P 节点上生效,请检查启动日志中与 profiling 相关的消息,例如 profiling_chunk_config 已启用以及块大小计算输出。

关键参数

  • --pipeline-parallel-size 2:启用流水线并行(必需,仅限 P 节点)
  • --enable-chunked-prefill:启用分块预填充(必需,仅限 P 节点)
  • --max-num-batched-tokens 32768:初始块大小(推荐用于 128k 序列)
  • profiling_chunk_config.enabled:启用动态分块流水线并行
  • profiling_chunk_config.smooth_factor:平滑因子(0 < x ≤ 1.0)。值越高,越信任动态预测
  • profiling_chunk_config.min_chunk:动态计算的最小块大小。应小于 max-num-batched-tokens
  • profiling_chunk_config.need_timing:启用/禁用在线校准
  • profiling_chunk_config.max_fit_chunk:在线校准的块时间数据数量。profiling 失败时应增大

使用 CPP 的 PD 分离关键点:

  • CPP(profiling_chunk_config.enabled、--pipeline-parallel-size > 1)仅在 P 节点上配置。
  • D 节点在不使用流水线并行的情况下运行(DP32 TP1 标准配置)——它们专注于低延迟逐 token 解码。
  • 完整的 PD 分离配置说明(环境验证、Mooncake 安装、代理部署),参见:

有关配置详情,参见功能指南。

在线校准

为获得最佳性能,请在生产环境前使用真实数据进行在线校准:

您可以使用 aisbench 生成长度固定的随机数据集。有关详情,参见使用 AISBench 进行性能评估。

  1. 修改 <YOUR_AISBENCH_PATH>/benchmark/ais_bench/datasets/synthetic/synthetic_config.py:

    synthetic_config = {
        "Type": "string",
        "RequestCount": 5,
        "TrustRemoteCode": False,
        "StringConfig": {
            "Input": {
                "Method": "uniform",
                "Params": {"MinValue": 131072, "MaxValue": 131072}  # Your max sequence length, max-model-len
            },
            "Output": {
                "Method": "uniform",
                "Params": {"MinValue": 1, "MaxValue": 1}
            }
        },
    }
    
  2. 运行在线校准:

    ais_bench --models vllm_api_stream_chat --datasets synthetic_gen --mode perf --debug
    

将在线校准数据长度配置为与 max-model-len 匹配。使用 batch_size=1,并确保数据不同,以避免在启用前缀缓存时命中缓存。

准确性评估

有关详情,参见使用 AISBench。

数据集 准确率
gsm8k 95.83

性能基准测试

有关详情,参见使用 AISBench 进行性能评估。

为评估动态分块流水线并行在 PD 分离长序列 LLM 推理场景中的效果,我们使用 DeepSeek-V3.1-W8A8 和 Qwen3-235B,在 Ascend Atlas 800T A3 服务器(64GB × 16)上部署 prefill 实例,配置和性能数据如下。

固定长度请求,并发=1:

  • DeepSeek-V3.1-W8A8:

    配置 CPP
    (动态分块,
    chunksize=32k)
    PP
    (静态分块,
    chunksize=32k)
    输入长度 128k TTFT: 22.5s TTFT: 27.0s
  • Qwen3-235B:

    配置 CPP
    (动态分块,
    chunksize=32k)
    PP
    (静态分块,
    chunksize=32k)
    输入长度 256k TTFT: 53.5s TTFT: 61.4s

可变长度请求,并发=4:

  • DeepSeek-V3.1-W8A8:

    配置 4k~64k 输入, mean=32k, std=32k
    前缀命中率=99%
    CPP2TP8 输入吞吐量: 22424 tps/card
    DP2TP8 输入吞吐量: 16150 tps/card
    TP16 输入吞吐量: 18875 tps/card

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 vl/vllm-ascend