跳到內容

專家並行部署

vLLM 支援專家並行 (EP),它允許將混合專家 (MoE) 模型中的專家部署在獨立的 GPU 上,從而整體提高區域性性、效率和吞吐量。

EP 通常與資料並行 (DP) 結合使用。雖然 DP 可以獨立於 EP 使用,但與 DP 結合使用時 EP 更高效。您可以在此處閱讀更多關於資料並行性的資訊。

先決條件

在使用 EP 之前,您需要安裝必要的依賴項。我們正在積極努力使未來的安裝過程更簡單

  1. 安裝 DeepEP 和 pplx-kernels:按照 vLLM 關於 EP 核心的指南設定主機環境此處
  2. 安裝 DeepGEMM 庫:遵循官方說明
  3. 對於解耦服務:按照指令碼安裝 UCX 和 NIXL。

後端選擇指南

vLLM 為 EP 提供了三種通訊後端

後端 用例 特性 最佳應用場景
pplx 單節點 支援分塊預填充 開發,最適用於節點內(單節點)部署
deepep_high_throughput 多節點預填充 帶連續佈局的 grouped GEMM 高吞吐量場景,預填充主導型工作負載
deepep_low_latency 多節點解碼 支援 CUDA graph,掩碼佈局 低延遲場景,解碼主導型工作負載

單節點部署

警告

EP 是一項實驗性功能。引數名稱和預設值未來可能會發生變化。

配置

透過設定 --enable-expert-parallel 標誌啟用 EP。EP 大小將自動計算為

EP_SIZE = TP_SIZE × DP_SIZE

其中:- TP_SIZE:張量並行大小(目前始終為 1)- DP_SIZE:資料並行大小- EP_SIZE:專家並行大小(自動計算)

示例命令

以下命令將部署一個 DeepSeek-V3-0324 模型,採用 1 路張量並行、8 路(注意力)資料並行和 8 路專家並行。注意力權重在所有 GPU 上覆制,而專家權重則在 GPU 之間分割。它將在一個配備 8 塊 GPU 的 H200(或 H20)節點上執行。對於 H100,您可以嘗試部署一個較小的模型或參考多節點部署部分。

# Single node EP deployment with pplx backend
VLLM_ALL2ALL_BACKEND=pplx VLLM_USE_DEEP_GEMM=1 \
    vllm serve deepseek-ai/DeepSeek-V3-0324 \
    --tensor-parallel-size 1 \      # Tensor parallelism across 1 GPU
    --data-parallel-size 8 \         # Data parallelism across 8 processes
    --enable-expert-parallel         # Enable expert parallelism

多節點部署

對於多節點部署,請使用 DeepEP 通訊核心,並選擇以下兩種模式之一(參見上方的後端選擇指南)。

部署步驟

  1. 每個節點執行一個命令 - 每個節點都需要自己的啟動命令
  2. 配置網路 - 確保正確的 IP 地址和埠配置
  3. 設定節點角色 - 第一個節點處理請求,其他節點以無頭模式執行

示例:2節點部署

以下示例展示了使用 deepep_low_latency 模式在 2 個節點上部署 DeepSeek-V3-0324 模型

# Node 1 (Primary - handles incoming requests)
VLLM_ALL2ALL_BACKEND=deepep_low_latency VLLM_USE_DEEP_GEMM=1 \
    vllm serve deepseek-ai/DeepSeek-V3-0324 \
    --tensor-parallel-size 1 \               # TP size per node
    --enable-expert-parallel \               # Enable EP
    --data-parallel-size 16 \                # Total DP size across all nodes
    --data-parallel-size-local 8 \           # Local DP size on this node (8 GPUs per node)
    --data-parallel-address 192.168.1.100 \  # Replace with actual IP of Node 1
    --data-parallel-rpc-port 13345 \         # RPC communication port, can be any port as long as reachable by all nodes
    --api-server-count=8                     # Number of API servers for load handling (scaling this out to total ranks are recommended)

# Node 2 (Secondary - headless mode, no API server)
VLLM_ALL2ALL_BACKEND=deepep_low_latency VLLM_USE_DEEP_GEMM=1 \
    vllm serve deepseek-ai/DeepSeek-V3-0324 \
    --tensor-parallel-size 1 \               # TP size per node
    --enable-expert-parallel \               # Enable EP
    --data-parallel-size 16 \                # Total DP size across all nodes
    --data-parallel-size-local 8 \           # Local DP size on this node
    --data-parallel-start-rank 8 \           # Starting rank offset for this node
    --data-parallel-address 192.168.1.100 \  # IP of primary node (Node 1)
    --data-parallel-rpc-port 13345 \         # Same RPC port as primary
    --headless                               # No API server, worker only

關鍵配置說明

  • 無頭模式:輔助節點使用 --headless 標誌執行,這意味著所有客戶端請求都由主節點處理
  • Rank 計算--data-parallel-start-rank 應等於先前節點的累積本地 DP 大小
  • 負載擴容:調整主節點上的 --api-server-count 以處理更高的請求負載

網路配置

InfiniBand 叢集

在 InfiniBand 網路叢集上,設定此環境變數以防止初始化掛起

export GLOO_SOCKET_IFNAME=eth0
這確保了 torch 分散式組發現使用乙太網而非 InfiniBand 進行初始設定。

專家並行負載均衡器 (EPLB)

儘管 MoE 模型通常經過訓練,使得每個專家接收相似數量的 token,但實際上 token 在專家之間的分佈可能高度不均勻。vLLM 提供專家並行負載均衡器 (EPLB) 以在 EP 排名之間重新分配專家對映,從而平衡專家之間的負載。

配置

使用 --enable-eplb 標誌啟用 EPLB。

模型支援

目前僅支援 DeepSeek V3 架構。

啟用後,vLLM 會在每次前向傳播時收集負載統計資料,並定期重新平衡專家分佈。

EPLB 引數

引數 描述 預設值
--eplb-window-size 用於再平衡決策跟蹤的引擎步數 -
--eplb-step-interval 再平衡頻率(每 N 個引擎步) -
--eplb-log-balancedness 記錄平衡性指標(每個專家的平均 token 數 ÷ 每個專家的最大 token 數) false
--num-redundant-experts 每個 EP 排名除了等量分配之外的額外全域性專家數量 0

專家分佈公式

  • 預設:每個 EP 排名擁有 NUM_TOTAL_EXPERTS ÷ NUM_EP_RANKS 個專家
  • 帶冗餘:每個 EP 排名擁有 (NUM_TOTAL_EXPERTS + NUM_REDUNDANT_EXPERTS) ÷ NUM_EP_RANKS 個專家

示例命令

啟用 EPLB 的單節點部署

# Single node with EPLB load balancing
VLLM_ALL2ALL_BACKEND=pplx VLLM_USE_DEEP_GEMM=1 vllm serve deepseek-ai/DeepSeek-V3-0324 \
    --tensor-parallel-size 1 \     # Tensor parallelism
    --data-parallel-size 8 \        # Data parallelism  
    --enable-expert-parallel \      # Enable EP
    --enable-eplb \                 # Enable load balancer
    --eplb-log-balancedness \       # Log balancing metrics
    --eplb-window-size 1000 \       # Track last 1000 engine steps
    --eplb-step-interval 3000       # Rebalance every 3000 steps

對於多節點部署,將這些 EPLB 標誌新增到每個節點的命令中。我們建議在大規模用例中將 --num-redundant-experts 設定為 32,以便最受歡迎的專家始終可用。

解耦服務(預填充/解碼分離)

對於需要嚴格 SLA 保證首個 token 時間和 token 間延遲的生產部署,解耦服務允許預填充和解碼操作獨立擴充套件。

架構概述

  • 預填充例項:使用 deepep_high_throughput 後端以獲得最佳預填充效能
  • 解碼例項:使用 deepep_low_latency 後端以獲得最小解碼延遲
  • KV 快取傳輸:透過 NIXL 或其他 KV 聯結器連線例項

設定步驟

  1. 安裝 KV 聯結器:使用安裝指令碼安裝 NIXL

  2. 配置兩個例項:將此標誌新增到預填充和解碼例項:--kv-transfer-config '{"kv_connector":"NixlConnector","kv_role":"kv_both"}

  3. 客戶端編排:使用下面的客戶端指令碼協調預填充/解碼操作。我們正在積極開發路由解決方案。

客戶端編排示例

from openai import OpenAI
import uuid

try:
    # 1: Set up clients for prefill and decode instances
    openai_api_key = "EMPTY"  # vLLM doesn't require a real API key

    # Replace these IP addresses with your actual instance addresses
    prefill_client = OpenAI(
        api_key=openai_api_key,
        base_url="http://192.168.1.100:8000/v1",  # Prefill instance URL
    )
    decode_client = OpenAI(
        api_key=openai_api_key,
        base_url="http://192.168.1.101:8001/v1",  # Decode instance URL  
    )

    # Get model name from prefill instance
    models = prefill_client.models.list()
    model = models.data[0].id
    print(f"Using model: {model}")

    # 2: Prefill Phase
    # Generate unique request ID to link prefill and decode operations
    request_id = str(uuid.uuid4())
    print(f"Request ID: {request_id}")

    prefill_response = prefill_client.completions.create(
        model=model,
        # Prompt must exceed vLLM's block size (16 tokens) for PD to work
        prompt="Write a detailed explanation of Paged Attention for Transformers works including the management of KV cache for multi-turn conversations",
        max_tokens=1,  # Force prefill-only operation
        extra_body={
            "kv_transfer_params": {
                "do_remote_decode": True,     # Enable remote decode
                "do_remote_prefill": False,   # This is the prefill instance
                "remote_engine_id": None,     # Will be populated by vLLM
                "remote_block_ids": None,     # Will be populated by vLLM
                "remote_host": None,          # Will be populated by vLLM
                "remote_port": None           # Will be populated by vLLM
            }
        },
        extra_headers={"X-Request-Id": request_id}
    )

    print("-" * 50)
    print("✓ Prefill completed successfully")
    print(f"Prefill response: {prefill_response.choices[0].text}")

    # 3: Decode Phase
    # Transfer KV cache parameters from prefill to decode instance
    decode_response = decode_client.completions.create(
        model=model,
        prompt="This prompt is ignored during decode",  # Original prompt not needed
        max_tokens=150,  # Generate up to 150 tokens
        extra_body={
            "kv_transfer_params": prefill_response.kv_transfer_params  # Pass KV cache info
        },
        extra_headers={"X-Request-Id": request_id}  # Same request ID
    )

    print("-" * 50)
    print("✓ Decode completed successfully")
    print(f"Final response: {decode_response.choices[0].text}")

except Exception as e:
    print(f"❌ Error during disaggregated serving: {e}")
    print("Check that both prefill and decode instances are running and accessible")