跳转至

动态分块流水线并行

Note

设计细节和数学模型请参见设计文档。部署教程请参见动态分块流水线并行教程

概述

动态分块流水线并行(CPP)是一种基于性能分析的动态分块策略,用于优化流水线并行(PP)场景下长序列的预填充性能。CPP 专为预填充-解码(PD)分离部署中的预填充器(P)节点设计。 通过基于性能分析数据动态计算最优分块大小,CPP 显著降低了 P 节点上长序列的首令牌时间(TTFT)。

:::{important} CPP 应在 PD 分离部署中的 P(预填充器)节点 上配置。D(解码器)节点无需配置 CPP。有关 PD 分离部署的指导,请参考以下教程:

使用场景

  • PD 分离 P 节点:在预填充器节点上启用 CPP,通过流水线并行优化长序列预填充。解码器节点无需 CPP。
  • 变长序列服务:PP 不会对短序列引入性能下降,并通过动态分块在长序列上获得收益。
  • 超长序列推理:对于超过单机内存容量的序列(例如 100 万 token),动态分块显著减少流水线空闲时间。

支持场景

CPP 专注于 PD 分离场景中 P 节点 预填充阶段的优化。它更适合在 PD 分离场景中使用。支持的特性如下:

Eager Graph Prefix
Cache
Chunked
Prefill
CPP

启用方法

PD 分离部署示例

在 PD 分离部署中,仅在 P(预填充器)节点 上启用 CPP。以下是使用 MooncakeConnector 实现 1P1D 架构的完整示例。

注意:

  • 目前已知 async-scheduling 可能导致 PP 预填充阶段性能下降,且 async-scheduling 对预填充的收益极小。因此,当前建议不要在 PP 的 P 节点上启用异步调度。
  • 建议使用 MooncakeConnectorV1 作为 kv_connector,因为它对 PP 提供了更全面的支持。

:::::{tab-set}

::::{tab-item} P 节点(预填充器 — 启用 CPP)

# 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=<COMMAND_RESULT>
local_ip=<YOUR_MACHINE_IP>

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 VLLM_ALLOW_LONG_MAX_MODEL_LEN=1

vllm serve Qwen/Qwen3-30B-A3B \
    --host 0.0.0.0 \
    --port 13700 \
    --served-model-name "qwen" \
    --tensor-parallel-size 2 \
    --pipeline-parallel-size 2 \
    --enforce-eager \
    --max-model-len 131072 \
    --max-num-batched-tokens 32768 \
    --enable-prefix-caching \
    --no-async-scheduling \
    --additional-config '{"profiling_chunk_config": {"enabled": true}}' \
    --kv-transfer-config \
    '{
        "kv_connector": "MooncakeConnectorV1",
        "kv_role": "kv_producer",
        "kv_port": "30000",
        "engine_id": "0",
        "kv_connector_extra_config": {
            "prefill": {
                "pp_size": 2,
                "dp_size": 1,
                "tp_size": 2
            },
            "decode": {
                "dp_size": 2,
                "tp_size": 2
            }
        }
    }'

::::

::::{tab-item} D 节点(解码器 — 不启用 CPP)

# 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=<COMMAND_RESULT>
local_ip=<YOUR_MACHINE_IP>

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 VLLM_ALLOW_LONG_MAX_MODEL_LEN=1

vllm serve Qwen/Qwen3-30B-A3B \
    --host 0.0.0.0 \
    --port 13701 \
    --served-model-name "qwen" \
    --data-parallel-size 2 \
    --tensor-parallel-size 2 \
    --enable-prefix-caching \
    --max-model-len 131072 \
    --max-num-batched-tokens 256 \
    --gpu-memory-utilization 0.9 \
    --compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
    --kv-transfer-config \
    '{
        "kv_connector": "MooncakeConnectorV1",
        "kv_role": "kv_consumer",
        "kv_port": "30000",
        "engine_id": "0",
        "kv_connector_extra_config": {
            "prefill": {
                "pp_size": 2,
                "dp_size": 1,
                "tp_size": 2
            },
            "decode": {
                "dp_size": 2,
                "tp_size": 2
            }
        }
    }'

::::{tab-item} 部署示例代理

在与预填充器服务实例相同的节点上运行代理服务器。您可以在仓库的示例中获取代理程序:load_balance_proxy_server_example.py

python load_balance_proxy_server_example.py \
    --host <PROXY_IP> \
    --port 8080 \
    --prefiller-hosts <PREFILL_MACHINE_IP> \
    --prefiller-port 13700 \
    --decoder-hosts <DECODE_MACHINE_IP> \
    --decoder-ports 13701
参数 含义
--port 代理端口
--prefiller-port 所有预填充端口
--decoder-ports 所有解码器端口

::::

::::{tab-item} 验证

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

curl http://<PROXY_IP>:8080/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "qwen",
        "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
    }'

::::

:::::

PD 分离与 CPP 的关键点:

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

配置参数

参数 类型 默认值 描述
enabled bool False 启用/禁用动态分块流水线并行
smooth_factor float 1.0 平滑因子(0 < x ≤ 1.0)。值越大,越信任动态预测结果
min_chunk int 4096 Minimum chunk size for dynamic calculation
need_timing bool True 启用/禁用在线校准
max_fit_chunk int 30 Number of chunk-time data for Online Calibration

参数调优

  • smooth_factor:控制对动态预测的信任程度
    • 1.0:严格遵循模型预测
    • 0.6~0.85:平衡动态调整与调度开销
    • 0.0:无动态调整(退化为固定分块)
  • min_chunk:通常无需调整。应小于 max-num-batched-tokens

推荐设置

max-num-batched-tokens

值得注意的是,CPP的TTFT对max-num-batched-tokens(视为动态求解的初始分块大小)非常敏感。 因为如果设置过大,会引入显著的计算空洞;如果设置过小,则会导致算子效率下降。为给动态调整留出足够空间,建议处理的序列越长,max-num-batched-tokens设置越大。推荐值:

序列长度 max-num-batched-tokens
64k 20480
128k 32768

在线校准

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

可使用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进行性能评估

为评估动态分块流水线并行在长序列LLM推理场景中的效果,我们使用**DeepSeek-V3.1-W8A8**和**Qwen3-235B**,在Ascend Atlas A3推理产品*64G(A3)上部署P实例,配置和性能数据如下。

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

  • DeepSeek-V3.1-W8A8:

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

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

变长请求,并发数=4

  • DeepSeek-V3.1-W8A8:

    配置 4k~64k 输入, 均值=32k, 标准差=32k
    前缀命中率=99%
    CPP2TP8 输入吞吐量:22424 tps/卡
    DP2TP8 输入吞吐量:16150 tps/卡
    PCP2TP8 输入吞吐量:18197 tps/卡
    TP16 输入吞吐量:18875 tps/卡

约束条件

  • 需要流水线并行--pipeline-parallel-size > 1
  • 需要分块预填充--enable-chunked-prefill
  • 与均衡调度不兼容:不能启用 VLLM_ASCEND_BALANCE_SCHEDULING
  • 启动开销:性能分析会增加约 64 次前向传播(数十秒)