跳到主要内容

快速开始


启动参数说明

Prefill、Decode 参数说明

在不同prefill、decode节点的启动脚本中需要更改和确认以下参数,个别参数的名字在不同示例脚本中有差别。

PREFILL_IP/DECODER_IP/MASTER_IP:Prefill 与 Decode 集群主节点(第1个节点)的IP和端口。

NODE_RANK:指Prefill或Decode集群的第几台机器。如果为2P4D,则 prefill 集群各节点的参数设为 01,decode 集群各节点的参数设为 0123

LOG_DIR:log日志保存路径。

MODEL_PATH:容器内模型路径。

NNODES/WORLD_SIZE: Prefill 或 Decode 集群的节点数。

SGLANG_PORT: Prefill 或 Decode 集群推理服务监听的端口号。

DEEP_EP_CONFIG: DeepEP的配置文件路径。

Router 参数说明

PREFILL_IP:与Prefill主节点IP和推理服务监听端口号相同。

DECODE_IP:与Decode主节点IP和推理服务监听端口号相同。

启动SGLang服务

本文档以 Qwen3.5-397B-A17B-FP8 为例,使用最小化部署方案 1P1D,即一台机器作为Prefill,一台机器为Decode。为获取更佳性能,推荐部署方式为1P4D,请参考 Qwen3.5 模型部署

虚拟环境

因容器环境里个别组件有不同版本,运行 SGLang 服务前需用命令切换 python 虚拟环境,并建议清理triton缓存。文档中大部分示例脚本已包含相关命令。

本 Qwen3.5 示例需要切换到 triton-3.2.0:workon triton-3.2.0 source ~/.virtualenvs/triton-3.2.0/bin/activate

清理triton缓存:rm -rf ~/.triton/cache/ && rm -r /tmp/*

一键运行说明

  • 将Prefill启动脚本,Decode启动脚本,Router启动脚本,一键运行脚本,包含节点IP的hostfile文件,DeepEP/EPLB等配置文件(如有),按需更新,置于同一路径下。建议使用挂载到容器里的 HOST 共享存储目录,如启动容器示例中的 /data/workspace,这样所有节点都可访问同一套文件。

  • hostfile文件记录了所有使用的机器,使用之前需要修改为本次部署使用的所有机器IP。

  • 一键运行脚本启动所有server,前置需求为所有节点均开启ssh service,且端口为run.sh中指定的端口(默认为62216),请参考启动容器 中的 bash命令 确保所有容器的ssh都正确启动在对应的端口。

  • 选择其中一台机器作为操作节点,运行一键运行脚本 run.sh 启动所有服务,各服务的log会输出到设置的 LOG_DIR 中。

bash run.sh

Prefill启动

prefill启动脚本 prefill_server.sh

#!/bin/bash
source ~/.virtualenvs/triton-3.2.0/bin/activate

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:/usr/local/musa/lib:$LD_LIBRARY_PATH
export PATH=/root/.local/bin:$PATH
export PATH=/root/.virtualenvs/triton-3.2.0/bin/:$PATH

export VLLM_PATCH_MUSA_CUSTOM_OPS=1

export MATE_FORCE_JIT=1

export MUSA_LAUNCH_BLOCKING=0
export MUSA_ENABLE_LLC_OPT=1

export TP_SOCKET_IFNAME=bond0
export GLOO_SOCKET_IFNAME=bond0

export MCCL_PROTOS=2
export MCCL_IB_GID_INDEX=3
export MCCL_NET_SHARED_BUFFERS=0

export MC_TE_METRIC=1
export MC_ENABLE_DEST_DEVICE_AFFINITY=1

export SGLANG_DEEP_GEMM_BLOCK_M=256
export SGLANG_SET_CPU_AFFINITY=1
export SGLANG_DEEPEP_BF16_DISPATCH=0
export SGLANG_ENABLE_TORCH_INFERENCE_MODE=true
export SGLANG_DISAGGREGATION_QUEUE_SIZE=8
export SGLANG_DISAGGREGATION_THREAD_POOL_SIZE=16
export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600
export SGLANG_DISAGGREGATION_MAPPING_IB_DEVICE_TO_GPU=1
export SGLANG_TORCH_PROFILER_DIR=$SCRIPT_DIR/traces
export SGLANG_EXPERT_DISTRIBUTION_RECORDER_DIR=$SCRIPT_DIR/traces

# 获取当前环境的 RDMA 设备名列表,在启动时作为 disaggregation-ib-device 参数值
IB_DEVS=()

for dev in /sys/class/infiniband/*; do
ibdev=$(basename "$dev")
for port in "$dev"/ports/*; do
# 速率(如 200 Gb/sec)
rate=$(cat "$port/rate" 2>/dev/null)
# link_layer: InfiniBand / Ethernet (RoCE)
link=$(cat "$port/link_layer" 2>/dev/null)
# 状态为 Up
state=$(cat "$port/state" 2>/dev/null)
# 只要是 200G/400G 且状态为 Up(IB 或 RoCE 都收)
if [[ "$rate" == *"200 Gb"* || "$rate" == *"400 Gb"* ]] && [[ "$state" == "4"* ]]; then
IB_DEVS+=("$ibdev")
break
fi
done
done
# 排序 + 去重
IB_DEVS_SORTED=$(printf "%s\n" "${IB_DEVS[@]}" | sort -V | uniq)
# 生成 MCCL / SGLang 变量
MCCL_IB_HCA=$(echo "$IB_DEVS_SORTED" | paste -sd, -)
SGLANG_IB_DEVICES="$MCCL_IB_HCA"
echo "IB_DEVICES=$MCCL_IB_HCA"
# 获取 RDMA 设备名列表结束

PREFILL_IP="${1}:5303" #Prefill 集群的 Master 节点 IP 及 端口
NODE_RANK=${2} #当前节点的编号,从 0 开始递增。
LOG_DIR=./logs
MODEL_PATH=/data/models/Qwen3.5-397B-A17B-FP8
NNODES=1
SGLANG_PORT=20133
DEEP_EP_CONFIG="$SCRIPT_DIR/deepep.config"

mkdir -p "${LOG_DIR}"
rm -rf ~/.triton/cache/ && rm -r /tmp/*
# 启动 SGLang
nohup python3 -m sglang.launch_server \
--model $MODEL_PATH \
--served-model-name qwen3.5-397b-a17b-fp8 \
--trust-remote-code \
--disable-cuda-graph \
--disable-overlap-schedule \
--tp-size 8 \
--ep-size 8 \
--dp-size 8 \
--pp-size ${NNODES} \
--moe-dense-tp-size 1 \
--enable-dp-lm-head \
--enable-dp-attention \
--moe-a2a-backend deepep \
--deepep-mode normal \
--mem-fraction-static 0.8 \
--attention-backend fa3 \
--mm-attention-backend fa3 \
--sampling-backend flashinfer \
--dist-init-addr ${PREFILL_IP} \
--nnodes ${NNODES} \
--node-rank ${NODE_RANK} \
--chunked-prefill-size -1 \
--disable-radix-cache \
--enable-cache-report \
--deepep-config "${DEEP_EP_CONFIG}" \
--schedule-conservativeness 1 \
--max-running-requests 64 \
--port ${SGLANG_PORT} \
--host 0.0.0.0 \
--load-balance-method round_robin \
--disaggregation-mode prefill \
--disaggregation-ib-device ${SGLANG_IB_DEVICES} > ${LOG_DIR}/prefill_server_$NODE_RANK.log 2>&1 &

加载成功参考日志

[2026-05-27 18:22:25] INFO: 127.0.0.1:48498 - "POST /v1/chat/completions HTTP/1.1" 400 Bad Request
[2026-05-27 18:22:25] Prefill disaggregation mode warm Up Failed, status code: 400
[2026-05-27 18:22:25] The server is fired up and ready to roll!

Decode启动

decoder启动脚本 decode_server.sh

#!/bin/bash
source ~/.virtualenvs/triton-3.2.0/bin/activate

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/:/usr/local/musa/lib:$LD_LIBRARY_PATH
export PATH=/root/.local/bin:$PATH
export PATH=/root/.virtualenvs/triton-3.2.0/bin/:$PATH

export VLLM_PATCH_MUSA_CUSTOM_OPS=1

export MATE_FORCE_JIT=1

export MUSA_LAUNCH_BLOCKING=0
export MUSA_ENABLE_LLC_OPT=1

export TP_SOCKET_IFNAME=bond0
export GLOO_SOCKET_IFNAME=bond0

export MCCL_PROTOS=2
export MCCL_IB_GID_INDEX=3
export MCCL_NET_SHARED_BUFFERS=0

export MC_TE_METRIC=1
export MC_ENABLE_DEST_DEVICE_AFFINITY=1

export SGLANG_SET_CPU_AFFINITY=1
export SGLANG_DEEPEP_BF16_DISPATCH=0
export SGLANG_DEEPEP_LL_USE_NVLINK=1
export SGLANG_DEEPEP_LL_DISABLE_RECV_HOOK=0
export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=128
export SGLANG_ENABLE_TORCH_INFERENCE_MODE=true
export SGLANG_DISAGGREGATION_QUEUE_SIZE=8
export SGLANG_DISAGGREGATION_THREAD_POOL_SIZE=16
export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600
export SGLANG_DISAGGREGATION_MAPPING_IB_DEVICE_TO_GPU=1
export SGLANG_BLACKWELL_OVERLAP_SHARED_EXPERTS_OUTSIDE_SBO=0
export SGLANG_TORCH_PROFILER_DIR=$SCRIPT_DIR/traces
export SGLANG_EXPERT_DISTRIBUTION_RECORDER_DIR=$SCRIPT_DIR/traces

# 获取当前环境的 RDMA 设备名列表,在启动时作为 disaggregation-ib-device 参数值
IB_DEVS=()

for dev in /sys/class/infiniband/*; do
ibdev=$(basename "$dev")
for port in "$dev"/ports/*; do
# 速率(如 200 Gb/sec)
rate=$(cat "$port/rate" 2>/dev/null)
# link_layer: InfiniBand / Ethernet (RoCE)
link=$(cat "$port/link_layer" 2>/dev/null)
# 状态为 Up
state=$(cat "$port/state" 2>/dev/null)
# 只要是 200G/400G 且状态为 Up(IB 或 RoCE 都收)
if [[ "$rate" == *"200 Gb"* || "$rate" == *"400 Gb"* ]] && [[ "$state" == "4"* ]]; then
IB_DEVS+=("$ibdev")
break
fi
done
done
# 排序 + 去重
IB_DEVS_SORTED=$(printf "%s\n" "${IB_DEVS[@]}" | sort -V | uniq)
# 生成 MCCL / SGLang 变量
MCCL_IB_HCA=$(echo "$IB_DEVS_SORTED" | paste -sd, -)
SGLANG_IB_DEVICES="$MCCL_IB_HCA"
echo "IB_DEVICES=$MCCL_IB_HCA"

DECODER_IP=${1}:5403 #Decode 集群的 Master 节点 IP 及 端口
NODE_RANK=${2} #当前节点的编号,从 0 开始递增。
LOG_DIR=./logs
MODEL_PATH=/data/models/Qwen3.5-397B-A17B-FP8
NNODES=1
SGLANG_PORT=20143

mkdir -p "${LOG_DIR}"
rm -rf ~/.triton/cache/ && rm -r /tmp/*
nohup python3 -m sglang.launch_server \
--model $MODEL_PATH \
--served-model-name qwen3.5-397b-a17b-fp8 \
--trust-remote-code \
--cuda-graph-bs $(seq 1 8) \
--disable-cuda-graph-padding \
--tp-size $((NNODES * 8)) \
--ep-size $((NNODES * 8)) \
--dp-size $((NNODES * 8)) \
--enable-dp-lm-head \
--moe-dense-tp-size 1 \
--enable-dp-attention \
--moe-a2a-backend deepep \
--deepep-mode low_latency \
--mem-fraction-static 0.83 \
--attention-backend fa3 \
--mm-attention-backend fa3 \
--sampling-backend flashinfer \
--max-running-requests 128 \
--dist-init-addr ${DECODER_IP} \
--nnodes ${NNODES} \
--node-rank ${NODE_RANK} \
--chunked-prefill-size -1 \
--disable-radix-cache \
--port ${SGLANG_PORT} \
--host 0.0.0.0 \
--decode-log-interval 1 \
--prefill-round-robin-balance \
--disaggregation-mode decode \
--disaggregation-ib-device ${SGLANG_IB_DEVICES} > ${LOG_DIR}/decode_server_$NODE_RANK.log 2>&1 &

加载成功参考日志

[2026-05-27 18:25:03] INFO: 127.0.0.1:42022 - "POST /v1/chat/completions HTTP/1.1" 400 Bad Request
[2026-05-27 18:25:03] Prefill disaggregation mode warm Up Failed, status code: 400
[2026-05-27 18:25:03] The server is fired up and ready to roll!

Router启动

Router 启动脚本 router.sh

#!/bin/bash
source ~/.virtualenvs/triton-3.2.0/bin/activate
export PATH=/root/.virtualenvs/triton-3.2.0/bin/:$PATH
PREFILL_IP="http://${1}:20133"
DECODER_IP="http://${2}:20143"
LOG_DIR=./logs

nohup python -m sglang_router.launch_router \
--pd-disaggregation \
--prefill $PREFILL_IP \
--decode $DECODER_IP \
--host 0.0.0.0 \
--request-timeout-secs 7200 \
--worker-startup-timeout-secs 600 \
--port 30000 > "${LOG_DIR}/router.log" 2>&1 &

router正常返回结果

INFO sglang_router_rs::middleware: src/middleware.rs:366: Starting concurrency queue processor
INFO sglang_router_rs::server: src/server.rs:721: Router ready | workers: [xxxxx]
INFO sglang_router_rs::server: src/server.rs:749: Starting server on 0.0.0.0:30000

DeepEP 配置文件

配置文件示例 deepep.config

{
"normal_dispatch": {
"num_sms": 60,
"num_max_nvl_chunked_send_tokens": 26
},
"normal_combine": {
"num_sms": 60,
"num_max_nvl_chunked_send_tokens": 16
}
}

创建 hostfile 文件

hostfile文件示例

192.168.100.101
192.168.100.102

一键启动所有服务

一键运行脚本 run.sh

#!/bin/bash
WORKSPACE=$(pwd)

# 检查 hostfile 是否存在
if [ ! -f "$WORKSPACE/hostfile" ]; then
echo "Error: $WORKSPACE/hostfile not found!"
exit 1
fi

# 读取 hostfile 到数组
mapfile -t hosts < "$WORKSPACE/hostfile"

echo "Using hosts:"
printf '%s\n' "${hosts[@]}"

# prefill - 使用第一个节点作为 prefill 服务器
ssh -p 62216 ${hosts[0]} "cd $WORKSPACE && bash prefill_server.sh ${hosts[0]} 0" &

# decode - 使用第二个节点作为 decoder 服务器
ssh -p 62216 ${hosts[1]} "cd $WORKSPACE && bash decode_server.sh ${hosts[1]} 0" &

# router - 在第一个节点上启动 router
ssh -p 62216 ${hosts[0]} "cd $WORKSPACE && bash router.sh ${hosts[0]} ${hosts[1]}" &

echo "All services started in background"

验证 SGLang 推理服务 API

在运行 Router 的机器上(若 --net host,容器内访问即可),验证是否有正常输出。预期返回 JSON,choices[0].message.content 为模型回复。

curl http://127.0.0.1:30000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3.5-397b-a17b-fp8",
"messages": [{"role": "user", "content": "你好,SGLang!"}],
"max_tokens": 100,
"temperature": 0.7
}'