1p1d#

一个 Prefill 组件,一个解码器 (1p1d) 示例#

此示例演示了如何在单个节点上使用 NIXL 以分离式 Prefill 运行 LMCache,配置为 1 个 Prefiller + 1 个 Decoder。此配置将计算密集型的 Prefill 操作与解码操作分离,从而实现更好的资源利用和性能优化。

架构概述#

1p1d 设置由三个主要组件组成:

  1. Prefill 服务器 - 处理推理的预填充阶段(初始提示处理)

  2. 解码服务器 - 处理推理的解码阶段(令牌生成)

  3. 代理服务器 - 协调预填充器和解码器之间的请求

       ┌─────────────┐
       │   Client    │
       └─────┬───────┘
     ┌───────▼───────┐
     │ Proxy Server  │
     │   Port 9100   │
     └───▲───────┬───┘
         │       │
┌────────▼──┐  ┌─▼────────┐
│ Prefiller │  │ Decoder  │
│Port 7100  │  │Port 7200 │
│  GPU 0    │  │  GPU 1   │
└───────────┘  └──────────┘
         ▲       ▲
         │       │
         └───────┘
          NIXL Transfer

先决条件#

  • LMCache: 使用 pip install lmcache 安装

  • NIXL: 从 NIXL GitHub 仓库 安装

  • 硬件:至少需要 2 个 GPU

  • 模型访问:有效的 Hugging Face 令牌 (HF_TOKEN) 用于 Llama 3.1 8B Instruct

快速开始#

  1. 设置您的 Hugging Face 令牌

    export HF_TOKEN=hf_your_token_here
    
  2. 导航到示例目录

    cd examples/disagg_prefill/1p1d_experimental
    
  3. 运行示例:

    bash disagg_example_1p1d.sh
    

该脚本将自动:

  • 在端口 7100(GPU 0)上启动一个 Prefill 实例

  • 在端口 7200 上启动解码器实例(GPU 1)

  • 在 9100 端口启动一个代理服务器

  • 等待所有服务器准备就绪

Ctrl+C 停止所有服务器。

配置#

重要:为了正确的 KV Cache 传输,请确保所有进程使用相同的 PYTHONHASHSEED 以保持 KV Cache 在进程间的一致性:

export PYTHONHASHSEED=0

分离式 Prefill 配置#

预填充器通过 configs/lmcache-prefiller-config.yaml 进行配置:

local_cpu: True
max_local_cpu_size: 5
max_local_disk_size: 0

enable_pd: True
transfer_channel: "nixl"
pd_role: "sender"
pd_proxy_host: "localhost"
pd_proxy_port: 7500
pd_buffer_size: 1073741824 # 1GB
pd_buffer_device: "cuda"

关键设置:

  • pd_role: "sender" - 配置此实例以发送 KV Cache 数据

  • pd_buffer_size: 1073741824 # 1GB - 传输的缓冲区大小

  • pd_buffer_device: "cuda" - 使用显存进行缓冲

解码器配置#

解码器通过 configs/lmcache-decoder-config.yaml 进行配置:

local_cpu: False
max_local_cpu_size: 0

enable_pd: True
transfer_channel: "nixl"
pd_role: "receiver"
pd_peer_host: "localhost"
pd_peer_init_port: 7300
pd_peer_alloc_port: 7400
pd_buffer_size: 2147483648 # 2GB
pd_buffer_device: "cuda"
nixl_backends: [UCX]

关键设置:

  • pd_role: "receiver" - 配置此实例以接收 KV Cache 数据

  • pd_buffer_size: 2147483648 # 2GB - 传输的缓冲区大小

  • pd_buffer_device: "cuda" - 使用显存进行缓冲

组件深入分析#

代理服务器 (disagg_proxy_server.py)#

代理服务器协调分离式 Prefill 工作流:

  1. 请求处理:在 9100 端口接收客户端请求

  2. 分离式 Prefill 协调: 发送请求给 Prefill 模块,max_tokens=1

  3. Prefill Response: 接收预填充器,表示 nixl 转移已完成

  4. 响应流:从解码器流式传输完整响应

  5. 性能监控:跟踪首次令牌时间(TTFT)统计信息

支持的端点:

  • /v1/completions

  • /v1/chat/completions

vLLM 服务器启动器 (disagg_vllm_launcher.sh)#

此脚本启动具有适当配置的单个 vLLM 服务器:

Prefill 启动命令:

UCX_TLS=cuda_ipc,cuda_copy,tcp \
   LMCACHE_CONFIG_FILE=$prefill_config_file \
   VLLM_ENABLE_V1_MULTIPROCESSING=1 \
   VLLM_WORKER_MULTIPROC_METHOD=spawn \
   CUDA_VISIBLE_DEVICES=0 \
   vllm serve $MODEL \
   --port 7100 \
   --disable-log-requests \
   --enforce-eager \
   --no-enable-prefix-caching \
   --kv-transfer-config \
   '{"kv_connector":"LMCacheConnectorV1","kv_role":"kv_producer","kv_connector_extra_config": {"discard_partial_chunks": false, "lmcache_rpc_port": "producer1"}}'

解码器启动命令:

UCX_TLS=cuda_ipc,cuda_copy,tcp \
   LMCACHE_CONFIG_FILE=$decode_config_file \
   VLLM_ENABLE_V1_MULTIPROCESSING=1 \
   VLLM_WORKER_MULTIPROC_METHOD=spawn \
   CUDA_VISIBLE_DEVICES=1 \
   vllm serve $MODEL \
   --port 7200 \
   --disable-log-requests \
   --enforce-eager \
   --no-enable-prefix-caching \
   --kv-transfer-config \
   '{"kv_connector":"LMCacheConnectorV1","kv_role":"kv_consumer","kv_connector_extra_config": {"discard_partial_chunks": false, "lmcache_rpc_port": "consumer1", "skip_last_n_tokens": 1}}'

测试与基准测试#

基本测试#

一旦所有服务器都在运行,您可以使用简单的 curl 命令进行测试:

curl -s -N -X POST http://127.0.0.1:9100/v1/completions   -H "Content-Type: application/json"   -d '{
   "model": "meta-llama/Llama-3.1-8B-Instruct",
   "prompt": "What date is today?",
   "max_tokens": 20,
   "temperature": 0.0
}'

性能基准测试#

要进行全面的性能测试,请使用 vLLM 的基准测试工具:

vllm bench serve --port 9100 --seed $(date +%s) \
    --model meta-llama/Llama-3.1-8B-Instruct \
    --dataset-name random --random-input-len 7500 --random-output-len 200 \
    --num-prompts 30 --burstiness 100 --request-rate 1 --ignore-eos

此基准测试: - 向 9100 端口(代理服务器)发送请求 - 使用 7500 个输入 token 的随机提示 - 每个请求生成 200 个输出 token - 使用 30 个总提示以 1 请求/秒的速度进行测试

日志文件和监控#

该示例生成三个用于监控的日志文件:

  • prefiller.log - Prefill 服务器日志和错误

  • decoder.log - 解码器服务器日志和错误

  • proxy.log - 代理服务器日志和 TTFT 统计信息

代理服务器每 5 秒自动计算并显示 TTFT 统计信息:

===============================
Num requests: 10
Prefill node TTFT stats:
 - Average (ms): 45.2
 - Median (ms): 43.1
 - 99th Percentile (ms): 52.8
===============================

故障排除#

常见问题#

  1. 显存:确保每个 GPU 具有足够的内存来支持模型

  2. NIXL 安装: 验证 NIXL 是否正确安装并可访问

  3. 端口冲突:检查端口 7100、7200 和 9000 是否可用

  4. HF Token: 确保您的 Hugging Face 令牌可以访问 Llama 模型

错误恢复#

如果任何服务器无法启动:

  1. 检查相应的日志文件以获取错误详情

  2. 使用 nvidia-smi 验证 GPU 可用性

  3. 确保所有依赖项已安装

  4. 尝试使用 Ctrl+C 重启,然后重新运行脚本。