Skip to content

vLLM Disaggregated Prefilling

vLLM 作为最流行的开源 LLM 推理引擎,从 v0.6.0 版本开始正式支持 DisaggregatedPrefilling (分散式预填充)。这一功能使得 vLLM 可以与 Mooncake 等 PD 分离系统无缝集成。

4.5.1 vLLM PD分离架构

4.5.2 KVTransferConfig 配置

vLLM 通过<font style="color:#ED740C;">KVTransferConfig</font>,这是启用 Disaggregated Prefilling的关键。

配置参数详解

python
from vllm import KVTransferConfig

 #   完整的KVTransferConfig配置示例
 kv_transfer_config = KVTransferConfig(         
      # ===传输层配置 ===
      # 传输后端类型: 'mooncake', 'pynccl', 'custom'
      kv_connector='mooncake',

      #   传输缓冲区大小 (GB)
      kv_buffer_size=2.0,

      #   是否启用KV Cache压缩
      kv_compression='fp8',    #   可选: None, 'fp8', 'int8'
          
      # ===角色配置 ===
      # 当前实例的角色: 'prefill', 'decode', 'both'
      kv_role='prefill',


      #   对端地址配置
      kv_ip='192.168.1.100',    #   对端IP
      kv_port=50051,            #   对端端口
     
      # === 性能调优 ===
      #   批量传输阈值
      kv_transfer_threshold=1024,      # tokens


      #   传输超时时间 (ms)
      kv_transfer_timeout=5000,


      #   是否启用异步传输
      kv_async_transfer=True,
 )

配置示例:Prefill节点

python
# prefill_server.py - Prefill      节点配置
from vllm import LLM, SamplingParams, KVTransferConfig


 #   配置KV传输
 kv_config = KVTransferConfig(
      kv_connector='mooncake',
      kv_role='prefill',
      kv_ip='decode-server.internal',      # Decode服务器地址
                                            
      kv_port=50051,
      kv_buffer_size=4.0,
      kv_compression='fp8',
 )


 #   初始化LLM引擎
 llm = LLM(
      model="meta-llama/Llama-2-70b",
      tensor_parallel_size=4,
      kv_transfer_config=kv_config,
              
      # Prefill优化配置
      max_num_seqs=64,          #   较大的批大小
      max_num_batched_tokens=8192,    # 大batch tokens
 )


 #   启动服务
 from vllm.entrypoints.openai.api_server import run_server
 run_server(llm, port=8000)

配置示例:Decode节点

python
# decode_server.py - Decode     节点配置
from vllm import LLM, SamplingParams, KVTransferConfig


  #   配置KV传输
  kv_config = KVTransferConfig(
       kv_connector='mooncake',
       kv_role='decode',
       kv_ip='0.0.0.0',    #   监听所有接口
       kv_port=50051,
       kv_buffer_size=8.0,     # Decode  需要更大的buffer
       kv_compression='fp8',
  )


  #   初始化LLM引擎
  llm = LLM(
       model="meta-llama/Llama-2-70b",
       tensor_parallel_size=4,
       kv_transfer_config=kv_config,
       # Decode优化配置
       max_num_seqs=256,          #   更大的批大小
       max_num_batched_tokens=2048,     # 较小的batch tokens
       #   启用连续批处理
       enable_chunked_prefill=False,        # Decode 节点不处理Prefill
  )


  #   启动服务
  run_server(llm, port=8001)

4.5.3 MooncakeConnector 实现

MooncakeConnector 是vLLM与Mooncake Transfer Engine的集成层。架构设计

python
# vllm/distributed/kv_transfer/mooncake_connector.py


class MooncakeConnector(KVConnectorBase):
   """
   Mooncake KV Cache   传输连接器
   功能:
   1. 与Mooncake Transfer Engine通信
   2. 管理KV Cache的发送和接收
   3. 处理压缩和解压缩
   """


   def __init__(self, config: KVTransferConfig):
         super().__init__(config)


         #   初始化Mooncake Transfer Engine客户端
         self.transfer_engine = MooncakeTransferEngine(
               buffer_size=config.kv_buffer_size,
               compression=config.kv_compression,
         )


         #   建立连接
         if config.kv_role == 'prefill':
               self._connect_to_decode(config.kv_ip, config.kv_port)
         else:   # decode
               self._start_listener(config.kv_ip, config.kv_port)


   def _connect_to_decode(self, ip: str, port: int):
         """Prefill  节点: 连接到Decode节点"""
         self.decode_conn = self.transfer_engine.connect(
               addr=f"{ip}:{port}",
               mode='rdma',   #   优先使用RDMA
         )


   def _start_listener(self, ip: str, port: int):
         """Decode  节点: 启动监听"""
         self.listener = self.transfer_engine.listen(
               addr=f"{ip}:{port}",
               on_receive=self._on_kv_received,
         )


   def send_kv_cache(
         self,
         request_id: str,
         kv_cache: torch.Tensor,
         metadata: Dict[str, Any],
   ) -> bool:
         """
         发送KV Cache到Decode节点
         Args:
             request_id:请求唯一标识    
             kv_cache: KV Cache 张量 [2, n_layers, n_heads, seq_len, d_head]
             metadata: 附加元数据(序列长度、模型版本等)


   Returns:
         发送是否成功
   """
   # 1.   压缩KV Cache
   if self.config.kv_compression == 'fp8':
         kv_cache = self._compress_fp8(kv_cache)


   # 2.   准备传输描述符
   transfer_desc = TransferDescriptor(
         request_id=request_id,
         data_ptr=kv_cache.data_ptr(),
         data_size=kv_cache.numel() * kv_cache.element_size(),
         metadata=metadata,
   )


   # 3.   执行传输
   try:
         self.transfer_engine.send(self.decode_conn, transfer_desc)
         return True
   except TransferError as e:
         logger.error(f"KV transfer failed: {e}")
         return False


    def receive_kv_cache(
       self,
       request_id: str,
       timeout: Optional[float] = None,
        ) -> Optional[torch.Tensor]:
        """
        接收KV Cache(Decode节点调用)
        Args:
        request_id:请求唯一标识
        timeout: 超时时间
        Returns:
        KV Cache张量,超时返回None
        """
        #   等待KV Cache到达
       kv_cache = self._wait_for_kv(request_id, timeout)
    
       if kv_cache is None:
             return None
    
       #   解压缩
       if self.config.kv_compression == 'fp8':
              kv_cache = self._decompress_fp8(kv_cache)
       return kv_cache


     def _compress_fp8(self, tensor: torch.Tensor) -> torch.Tensor:               
          """FP8压缩"""
          # 使用NVIDIA的FP8格式
          scale = tensor.abs().max() / 448.0   # E4M3格式最大值                                              
          compressed = (tensor / scale).to(torch.float8_e4m3fn)
          return compressed, scale


      def _decompress_fp8(
          self,
          compressed: torch.Tensor,
          scale: float
      ) -> torch.Tensor:
          """FP8  解压缩"""
          return compressed.to(torch.float16) * scale

4.5.4 PyNcclConnector 实现

PyNcclConnector是基于NCCL的KV Cache传输实现,适用于单机多GPU场景。

python
# vllm/distributed/kv_transfer/pynccl_connector.py

class PyNcclConnector(KVConnectorBase):
   """
   基于NCCL的KV Cache传输连接器
   适用场景:
   - 单机多GPU PD分离
   - NVLink高速互联
   """


   def __init__(self, config: KVTransferConfig):
         super().__init__(config)

         #   初始化NCCL通信组
         self.nccl_comm = self._init_nccl_comm()


   def _init_nccl_comm(self) -> nccl.Comm:
         """初始化NCCL通信组"""
         # 获取GPU设备
         local_rank = int(os.environ.get('LOCAL_RANK', 0))
         torch.cuda.set_device(local_rank)

         #   初始化NCCL
         comm = nccl.Comm(
               nranks=self.world_size,
               rank=self.rank,
         )
         return comm


   def send_kv_cache(
         self,
         request_id: str,
         kv_cache: torch.Tensor,
         dst_rank: int,
   ) -> bool:
         """使用NCCL发送KV Cache"""
         # NCCL发送
         nccl.send(
               sendbuf=kv_cache.data_ptr(),
               count=kv_cache.numel(),
               datatype=nccl.float16,
               dst=dst_rank,
               comm=self.nccl_comm,
         )
         return True


   def receive_kv_cache(
           self,
           request_id: str,
           shape: Tuple[int, ...],
           src_rank: int,
        ) -> torch.Tensor:
           """使用NCCL接收KV Cache"""
           # 预分配接收缓冲区
           recv_buffer = torch.empty(
                 shape,
                 dtype=torch.float16,
                 device='cuda',
           )

           # NCCL接收
           nccl.recv(
                 recvbuf=recv_buffer.data_ptr(),
                 count=recv_buffer.numel(),
                 datatype=nccl.float16,
                 src=src_rank,
                 comm=self.nccl_comm,
           )
           return recv_buffer

4.5.5 集成配置示例

python
# 完整的vLLM + Mooncake PD分离配置

# docker-compose.yml
version: '3.8'

services:
  prefill-server:
    image: vllm/vllm-openai:latest
    runtime: nvidia
    environment:
      - CUDA_VISIBLE_DEVICES=0,1,2,3
      - VLLM_KV_CONNECTOR=mooncake
      - VLLM_KV_ROLE=prefill
      - VLLM_KV_DECODE_IP=decode-server
      - VLLM_KV_DECODE_PORT=50051
    command: >
      python -m vllm.entrypoints.openai.api_server
      --model meta-llama/Llama-2-70b
      --tensor-parallel-size 4
      --max-num-seqs 64
      --max-num-batched-tokens 8192
      --port 8000
    networks:
      - pd-network

  decode-server:
    image: vllm/vllm-openai:latest
    runtime: nvidia
    environment:
      - CUDA_VISIBLE_DEVICES=4,5,6,7
      - VLLM_KV_CONNECTOR=mooncake
      - VLLM_KV_ROLE=decode
      - VLLM_KV_LISTEN_PORT=50051
    command: >
      python -m vllm.entrypoints.openai.api_server
      --model meta-llama/Llama-2-70b
      --tensor-parallel-size 4
      --max-num-seqs 256
      --max-num-batched-tokens 2048
      --port 8001
    networks:
      - pd-network

  mooncake-transfer:
    image: mooncake/transfer-engine:latest
    privileged: true
    environment:
      - MOONCAKE_RDMA_DEVICE=mlx5_0
      - MOONCAKE_BUFFER_SIZE=16G
    volumes:
        - /dev/infiniband:/dev/infiniband
    networks:
        - pd-network
networks:
   pd-network:
      driver: bridge

用心记录,持续成长