分离式部署
LLM大模型推理分为Prefill和Decode两个阶段,分别为计算密集型和访存密集型。
- Prefill阶段:处理输入的全部Token,完成模型的前向计算(Forward),生成首token。
- Decode阶段:基于首token和缓存的KV Cache,生成其他token;假定总共输出N个token,Decode阶段需要执行(N-1)次前向计算。
分离式部署是将Prefill和Decode部署在不同的计算资源上,各自使用最佳的配置,可以提高硬件利用率、提高吞吐、降低整句时延。
分离式部署相比集中式部署,实现的核心差异在于KV Cache传输和请求调度。
KV Cache 传输
在分离式部署中,请求在Prefill实例中生成的KV Cache,需要传输至Decode实例。FastDeploy提供了2种传输方式,分别针对单机内与多机间的场景。
单机内传输:通过cudaMemcpyPeer进行单机内两个GPU之间KV Cache传输。
多机间传输:使用自研的RDMA传输库在多机之间传输KV Cache。
PD 分离请求调度
针对PD分离式部署,FastDeploy提供Python版本Router来实现请求收发和请求调度。使用方式和调度流程如下: * 启动Router * 启动PD实例,PD实例会注册到Router * 用户请求发送到Router * Router根据PD实例的负载情况为请求选择合适的PD实例对 * Router将请求发给选定的PD实例 * P实例收到请求后向D实例申请Cache Block * P实例推理生成首token,同时layerwise传输Cache给D实例,完成后将首token发送给Router和D实例 * D实例收到请求和首token后,继续生成后续token,发送给Router * Router接收PD实例的生成结果,返回给用户
高性能版本Router正在开发中,敬请期待。
使用说明
基于Router多机分离式部署
环境准备
大家可以参考文档准备环境,推荐使用Docker。 如果是自行准备运行环境,需要确保安装RDMA依赖包(librdmacm-dev libibverbs-dev iproute2)和驱动MLNX_OFED。
apt update --fix-missing
apt-get install -y librdmacm-dev libibverbs-dev iproute2
# 下载并安装MLNX_OFED
./mlnxofedinstall --user-space-only --skip-distro-check --without-fw-update --force --without-ucx-cuda
拉取FastDeploy最新代码,编译安装(最新release 2.3和2.4版本还没有最新分离式部署的功能特性)。
git clone https://github.com/PaddlePaddle/FastDeploy
cd FastDeploy
bash build.sh
部署服务
快速上手
启动Router服务,其中--splitwise参数指定为分离式部署的调度方式,日志信息输出在log_router/router.log。
export FD_LOG_DIR="log_router"
python -m fastdeploy.router.launch \
--host 0.0.0.0 \
--port 30000 \
--splitwise
启动Prefill实例。对比单机部署,增加--splitwise-role参数指定实例角色为Prefill,增加--router参数指定Router的接口,其他参数和单机部署相同。
export CUDA_VISIBLE_DEVICES=0
export FD_LOG_DIR="log_prefill"
python -m fastdeploy.entrypoints.openai.api_server \
--model "PaddlePaddle/ERNIE-4.5-0.3B-Paddle" \
--port 31000 \
--splitwise-role prefill \
--router "0.0.0.0:30000"
启动Decode实例。
export CUDA_VISIBLE_DEVICES=1
export FD_LOG_DIR="log_decode"
python -m fastdeploy.entrypoints.openai.api_server \
--model "PaddlePaddle/ERNIE-4.5-0.3B-Paddle" \
--port 32000 \
--splitwise-role decode \
--router "0.0.0.0:30000"
Prefill和Decode实例启动成功,并且向Router注册成功后,可以发送请求。
curl -X POST "http://0.0.0.0:30000/v1/chat/completions" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "hello"}
],
"max_tokens": 100,
"stream": false
}'
具体说明
分离式部署启动Prefill/Decode实例的参数说明如下,其他参数设置和mixed部署类似,具体参考文档:
* --splitwise-role: 指定实例角色,可选值为prefill,decode和mixed,默认是mixed
* --cache-transfer-protocol: 指定KV Cache传输协议,可选值为rdma和ipc,默认是rdma,ipc;PD实例在同一台机器,支持两种传输方式,优先使用ipc传输;PD实例不在同一台机器,只支持rdma传输;如果使用rdma传输,需要确保多台机器的RDMA网络互通
* --rdma-comm-ports: 指定RDMA通信端口,多个端口用逗号隔开,端口数量需要和dp_size*tp_size相同;可以不指定,FD内部会找空闲的端口
* --pd-comm-port: 指定PD实例的交互接口,多个端口用逗号隔开,端口数量需要和dp_size相同;可以不指定,FD内部会找空闲的端口
* --router:指定Router的服务地址
注意:
* 如果想手动指定RDMA网卡,可以设置KVCACHE_RDMA_NICS环境变量,多个网卡名用逗号隔开,Fastdeploy提供了检测RDMA网卡的脚本bash FastDeploy/scripts/get_rdma_nics.sh <device>, 其中 cpu 或 gpu。如果不设置KVCACHE_RDMA_NICS环境变量, Fastdeploy内部会自动检测可用的RDMA网卡。
* 分离式部署也可以使用benchmark工具向Router服务发请求,开启--pd-metrics参数可以统计到更多分析指标。
* 根据Decode实例的显存资源和最大处理请求数max_num_seqs来调整请求并发,如果请求并发很高但是Decode资源不足,Prefill会为特定请求持续向Decode申请资源,导致Prefill资源利用率过低;设置export PREFILL_CONTINUOUS_REQUEST_DECODE_RESOURCES=0'来关闭该行为,特定请求遇到Decode资源不足会直接向Router返回错误。
* 分离式部署支持多种并行策略,如果使用DP并行,必须使用python -m fastdeploy.entrypoints.openai.multi_api_server`来启动服务。
Examples示例
PD分离式部署支持前缀缓存、TP并行、DP并行等特性,具体examples可以参考examples/splitwise。
基于SplitwiseScheduler多机分离式部署
注意:不推荐使用SplitwiseScheduler,推荐使用Router来做请求调度。
环境准备
- 使用
conda安装
⚠️ 注意 Redis 版本要求:6.2.0 及以上 低于此版本可能不支持所需的命令。
# 安装
conda install redis
# 启动
nohup redis-server > redis.log 2>&1 &
- 使用
apt安装
# 安装
sudo apt install redis-server -y
# 启动
sudo systemctl start redis-server
- 使用
yum安装
# 安装
sudo yum install redis -y
# 启动
sudo systemctl start redis
部署服务
多机部署时需要确认当前网卡是否支持RDMA,并且需要集群中所有节点网络互通。
注意:
* KVCACHE_RDMA_NICS 指定当前机器的RDMA网卡,多个网卡用逗号隔开。
* 仓库中提供了自动检测RDMA网卡的脚本 bash scripts/get_rdma_nics.sh <device>, 其中 cpu 或 gpu。
prefill 实例
export FD_LOG_DIR="log_prefill"
export CUDA_VISIBLE_DEVICES=0,1,2,3
export ENABLE_V1_KVCACHE_SCHEDULER=0
echo "set RDMA NICS"
export $(bash scripts/get_rdma_nics.sh gpu)
echo "KVCACHE_RDMA_NICS ${KVCACHE_RDMA_NICS}"
python -m fastdeploy.entrypoints.openai.api_server \
--model ERNIE-4.5-300B-A47B-BF16 \
--port 8180 --metrics-port 8181 \
--engine-worker-queue-port 8182 \
--cache-queue-port 8183 \
--tensor-parallel-size 4 \
--quantization wint4 \
--cache-transfer-protocol "rdma,ipc" \
--rdma-comm-ports "7671,7672,7673,7674" \
--pd-comm-port "2334" \
--splitwise-role "prefill" \
--scheduler-name "splitwise" \
--scheduler-host "127.0.0.1" \
--scheduler-port 6379 \
--scheduler-topic "test" \
--scheduler-ttl 9000
decode 实例
export FD_LOG_DIR="log_decode"
export CUDA_VISIBLE_DEVICES=4,5,6,7
export ENABLE_V1_KVCACHE_SCHEDULER=0
echo "set RDMA NICS"
export $(bash scripts/get_rdma_nics.sh gpu)
echo "KVCACHE_RDMA_NICS ${KVCACHE_RDMA_NICS}"
python -m fastdeploy.entrypoints.openai.api_server \
--model ERNIE-4.5-300B-A47B-BF16 \
--port 8184 --metrics-port 8185 \
--engine-worker-queue-port 8186 \
--cache-queue-port 8187 \
--tensor-parallel-size 4 \
--quantization wint4 \
--scheduler-name "splitwise" \
--cache-transfer-protocol "rdma,ipc" \
--rdma-comm-ports "7671,7672,7673,7674" \
--pd-comm-port "2334" \
--scheduler-host "127.0.0.1" \
--scheduler-port 6379 \
--scheduler-ttl 9000
--scheduler-topic "test" \
--splitwise-role "decode"
参数说明:
- --splitwise-role: 指定当前服务为prefill还是decode
- --cache-queue-port: 指定cache服务的端口,用于prefill和decode服务通信
多机参数说明:
- --cache-transfer-protocol: 指定KV Cache传输协议,支持ipc和rdma,默认ipc
- --scheduler-name: PD分离情况下为splitwise
- --scheduler-host: 连接的redis地址
- --scheduler-port: 连接的redis端口
- --scheduler-ttl: 指定redis的ttl时间,单位为秒
- --scheduler-topic: 指定redis的topic
- --pd-comm-port: 指定pd通信的端口
- --rdma-comm-ports: 指定RDMA通信的端口,多个端口用逗号隔开,数量与卡数一致