9
模型应用
海光K100-AI双实例部署qwen3.5-122B实录
2026-05-28 15:58:16
388
# Qwen3.5-122B-A10B-GPTQ-Int4 部署实录 ## 一、下载模型 ### 1. 创建模型存储目录 ```bash mkdir -p /models ``` ### 2. 安装 ModelScope 下载工具 ```bash pip install modelscope ``` ### 3. 后台下载模型 ```bash nohup modelscope download --model Qwen/Qwen3.5-122B-A10B-GPTQ-Int4 \ --local_dir /models/Qwen3.5-122B-A10B-GPTQ-Int4 > /tmp/dl.log 2>&1 & ``` ### 4. 确认下载进程 ```bash sleep 10 && tail -5 /tmp/dl.log ``` --- ## 二、部署 vLLM 推理服务 > 每次重启主机后需清理旧容器再重建:`docker rm -f llm-server` ### 1. 系统优化 ```bash # 关闭 NUMA 平衡(避免跨节点内存迁移导致性能下降) sudo sh -c 'echo 0 > /proc/sys/kernel/numa_balancing' ``` ### 2. 启动 Docker 容器 ```bash docker run -dit \ --shm-size 200g \ --network=host \ --name llm-server \ --privileged \ --device=/dev/kfd \ --device=/dev/dri \ --device=/dev/mkfd \ --group-add video \ --cap-add=SYS_PTRACE \ --security-opt seccomp=unconfined \ -u root \ -v /opt/hyhal/:/opt/hyhal/:ro \ -v /models:/models \ harbor.sourcefind.cn:5443/dcu/admin/base/custom:vllm018-ubuntu22.04-dtk26.04-gemma4-0413 \ bash ``` > **说明:** 挂载 `/dev/kfd`、`/dev/dri`、`/dev/mkfd` 用于 DCU 设备透传;`/opt/hyhal` 为海光 HAL 层只读挂载。 ### 3. 启动双实例 vLLM 服务 > **为什么不使用 8 卡 TP?** K100-AI 采用 PCIe 互联(32 GB/s),8 卡 TP 时 all-reduce 通信占总耗时 80%+,输出速度约 24 t/s。双实例 4 卡 TP 方案下每组内部通信量减半,组间零通信,实测输出速度提升至 25\~27 t/s,且并发吞吐翻倍。 **GPU-NUMA 拓扑映射:** | DCU 卡 | NUMA 节点 | CPU 核心 | |--------|----------|---------| | 卡 0\~3 | NUMA 节点 3 | 24\~31, 88\~95 | | 卡 4\~7 | NUMA 节点 7 | 56\~63, 120\~127 | **实例 1(卡 0\~3,端口 8002):** ```bash docker exec -d llm-server bash -c ' export HIP_VISIBLE_DEVICES=0,1,2,3 export ALLREDUCE_STREAM_WITH_COMPUTE=1 nohup vllm serve /models/Qwen3.5-122B-A10B-GPTQ-Int4 \ --port 8002 \ --trust-remote-code \ --dtype float16 \ --quantization gptq \ --tensor-parallel-size 4 \ --gpu-memory-utilization 0.90 \ --max-model-len 8192 \ --served-model-name Qwen3.5-122B \ --default-chat-template-kwargs '\''{"enable_thinking": false}'\'' \ --reasoning-parser qwen3 \ --enable-auto-tool-choice \ --tool-call-parser qwen3_coder > /tmp/llm1.log 2>&1 & ' ``` **实例 2(卡 4\~7,端口 8003):** ```bash docker exec -d llm-server bash -c ' export HIP_VISIBLE_DEVICES=4,5,6,7 export ALLREDUCE_STREAM_WITH_COMPUTE=1 nohup vllm serve /models/Qwen3.5-122B-A10B-GPTQ-Int4 \ --port 8003 \ --trust-remote-code \ --dtype float16 \ --quantization gptq \ --tensor-parallel-size 4 \ --gpu-memory-utilization 0.90 \ --max-model-len 8192 \ --served-model-name Qwen3.5-122B \ --default-chat-template-kwargs '\''{"enable_thinking": false}'\'' \ --reasoning-parser qwen3 \ --enable-auto-tool-choice \ --tool-call-parser qwen3_coder > /tmp/llm2.log 2>&1 & ' ``` **关键参数说明:** | 参数 | 含义 | |------|------| | `HIP_VISIBLE_DEVICES` | 指定使用的 DCU 卡,实例1 用 0\~3,实例2 用 4\~7 | | `ALLREDUCE_STREAM_WITH_COMPUTE=1` | all-reduce 与计算重叠,减少通信等待 | | `--quantization gptq` | GPTQ-Int4 量化推理 | | `--tensor-parallel-size 4` | 每实例 4 卡张量并行 | | `--gpu-memory-utilization 0.90` | GPU 显存占用上限 90% | | `--max-model-len 8192` | 最大上下文长度 8K | | `--default-chat-template-kwargs {"enable_thinking": false}` | 关闭思维链,减少输出 token 数 | | `--enable-auto-tool-choice` | 启用工具调用 | ### 4. 等待模型加载 ```bash sleep 300 && docker exec llm-server bash -c 'tail -3 /tmp/llm1.log' docker exec llm-server bash -c 'tail -3 /tmp/llm2.log' ``` > 模型加载通常需要 5\~8 分钟,日志中出现 `Application startup complete` 即表示服务就绪。 ### 5. 预热(触发 CUDA Graph 编译) ```bash for i in 1 2 3; do curl -s http://localhost:8002/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"Qwen3.5-122B","messages":[{"role":"user","content":"你好"}],"max_tokens":32}' > /dev/null curl -s http://localhost:8003/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"Qwen3.5-122B","messages":[{"role":"user","content":"你好"}],"max_tokens":32}' > /dev/null done ``` > 首次请求会触发 CUDA Graph 编译,耗时约 30 秒,预热后速度正常。 --- ## 三、Nginx 负载均衡 ### 1. 安装 Nginx ```bash apt install -y nginx ``` ### 2. 配置负载均衡 ```bash cat > /etc/nginx/conf.d/llm-lb.conf << 'EOF' upstream llm_backend { least_conn; server 127.0.0.1:8002; server 127.0.0.1:8003; } server { listen 8001; client_max_body_size 200m; location / { proxy_pass http://llm_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 300s; proxy_buffering off; proxy_set_header Connection ''; proxy_http_version 1.1; chunked_transfer_encoding off; } } EOF ``` ### 3. 启动 Nginx ```bash # 首次启动 nginx # 后续修改配置后重载 nginx -s reload ``` ### 4. 验证负载均衡 ```bash # 分别测试两个实例 curl -s http://localhost:8002/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"Qwen3.5-122B","messages":[{"role":"user","content":"你好"}],"max_tokens":32}' curl -s http://localhost:8003/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"Qwen3.5-122B","messages":[{"role":"user","content":"你好"}],"max_tokens":32}' # 测试 Nginx 负载均衡 curl -s http://localhost:8001/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"Qwen3.5-122B","messages":[{"role":"user","content":"你好"}],"max_tokens":32}' ``` > 三个请求均返回正常 JSON 响应即表示负载均衡配置成功。 --- ## 四、Open WebUI 部署 ### 1. 拉取镜像 ```bash # 配置 Docker 镜像加速源 sudo tee /etc/docker/daemon.json << 'EOF' { "registry-mirrors": [ "https://mirror.ccs.tencentyun.com", "https://docker.1panel.live", "https://hub.rat.dev" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker # 拉取 Open WebUI 镜像 docker pull dyrnq/open-webui:main ``` ### 2. 启动 Open WebUI ```bash docker run -dit \ --name open-webui \ --network=host \ -v /data/open-webui:/app/backend/data \ -e OPENAI_API_BASE_URLS="http://localhost:8001/v1" \ -e OPENAI_API_KEYS="EMPTY" \ -e RAG_EMBEDDING_ENGINE="openai" \ -e RAG_EMBEDDING_BASE_URL="http://localhost:8001/v1" \ -e RAG_EMBEDDING_MODEL="Qwen3.5-122B" \ -e ENABLE_RAG_WEB_SEARCH="false" \ -e HF_HUB_OFFLINE="1" \ -e TRANSFORMERS_OFFLINE="1" \ --restart unless-stopped \ dyrnq/open-webui:main ``` **关键环境变量说明:** | 变量 | 值 | 说明 | |------|---|------| | `OPENAI_API_BASE_URLS` | `http://localhost:8001/v1` | 对接 Nginx 负载均衡地址 | | `OPENAI_API_KEYS` | `EMPTY` | vLLM 不校验 Key,随便填 | | `HF_HUB_OFFLINE` | `1` | 禁止从 HuggingFace 下载(无外网) | | `TRANSFORMERS_OFFLINE` | `1` | 禁止在线下载 Transformers 模型 | | `RAG_EMBEDDING_ENGINE` | `openai` | 嵌入引擎使用 OpenAI 兼容接口 | ### 3. 访问 Open WebUI 浏览器打开: ``` http://192.168.39.232:8080 ``` 首次访问需注册管理员账号,登录后确认: - **API 地址**:`http://localhost:8001/v1` - **模型名**:`Qwen3.5-122B` - **API Key**:`EMPTY` ### 4. 如果 Open WebUI 无法启动 ```bash # 查看容器状态 docker ps | grep open-webui # 查看启动日志 docker logs open-webui --tail 30 # 如果显示 HuggingFace 下载失败,确认环境变量 HF_HUB_OFFLINE=1 docker rm -f open-webui # 重新按步骤 2 启动 ``` --- ## 五、性能基准测试 ### 1. 测试脚本 ```bash cat > /tmp/llm-bench.sh << 'SCRIPT' #!/bin/bash BASE_URL="http://localhost:8001/v1/chat/completions" MODEL="Qwen3.5-122B" PROMPT="你好,请用一句话介绍通义千问3.5模型" MAX_TOKENS=128 ROUNDS=5 echo "==========================================" echo " LLM Speed 基准测试" echo "==========================================" echo "目标: $BASE_URL" echo "模型: $MODEL" echo "轮次: $ROUNDS | max_tokens: $MAX_TOKENS" echo "------------------------------------------" total_ttft=0 total_speed=0 total_time=0 success=0 fail=0 for i in $(seq 1 $ROUNDS); do result=$(curl -s -w "\n%{time_starttransfer} %{time_total}" \ "$BASE_URL" \ -H "Content-Type: application/json" \ -d "{\"model\":\"$MODEL\",\"messages\":[{\"role\":\"user\",\"content\":\"$PROMPT\"}],\"temperature\":0.7,\"max_tokens\":$MAX_TOKENS}") timing=$(echo "$result" | tail -1) ttft=$(echo "$timing" | awk '{print $1}') total=$(echo "$timing" | awk '{print $2}') json=$(echo "$result" | sed '$d') completion_tokens=$(echo "$json" | python3 -c " import sys,json try: r=json.load(sys.stdin) print(r.get('usage',{}).get('completion_tokens',0)) except: print(0) " 2>/dev/null) if [ "$completion_tokens" -gt 0 ] 2>/dev/null; then speed=$(echo "$completion_tokens $total" | awk '{printf "%.2f", $1/$2}') ttft_ms=$(echo "$ttft" | awk '{printf "%.0f", $1*1000}') echo " 第${i}轮 | 首字:${ttft_ms}ms | 总时:${total}s | tokens:${completion_tokens} | 速度:${speed} t/s" total_ttft=$(echo "$total_ttft $ttft" | awk '{printf "%.4f", $1+$2}') total_speed=$(echo "$total_speed $speed" | awk '{printf "%.2f", $1+$2}') total_time=$(echo "$total_time $total" | awk '{printf "%.2f", $1+$2}') success=$((success+1)) else echo " 第${i}轮 | 失败" fail=$((fail+1)) fi done echo "==========================================" if [ $success -gt 0 ]; then avg_ttft=$(echo "$total_ttft $success" | awk '{printf "%.0f", $1/$2*1000}') avg_speed=$(echo "$total_speed $success" | awk '{printf "%.2f", $1/$2}') avg_time=$(echo "$total_time $success" | awk '{printf "%.2f", $1/$2}') qps=$(echo "$success $total_time" | awk '{printf "%.2f", $1/$2}') echo " 成功: $success | 失败: $fail" echo " 平均首字延迟: ${avg_ttft}ms" echo " 平均输出速度: ${avg_speed} t/s" echo " 平均总时间: ${avg_time}s" echo " QPS: $qps" else echo " 全部失败,请检查服务状态" fi echo "==========================================" SCRIPT chmod +x /tmp/llm-bench.sh ``` ### 2. 运行测试 ```bash bash /tmp/llm-bench.sh ``` ### 3. 实测性能数据 | 方案 | 平均输出速度 | 平均首字延迟 | 并发 QPS | |------|------------|------------|---------| | 8 卡 TP=8 单实例 | ~24 t/s | ~3.3s | 0.76 | | **4 卡 TP=4 双实例** | **~25 t/s** | **~2.0s** | **~0.5/实例** | | 双实例合计吞吐 | ~25 t/s × 2 | ~2.0s | **~1.0** | **性能瓶颈分析:** Qwen3.5-122B-A10B 是 MoE 模型(122B 总参数,10B 激活),GPU 计算只需 ~8ms/token,但 4 卡 all-reduce 通信走 PCIe 需 ~30ms/token。通信占总耗时 80%,是当前硬件下的性能天花板。量化方式、CPU、内存、硬盘均不是瓶颈。 --- ## 六、服务架构总览 ``` ┌──────────────────────┐ │ Open WebUI :8080 │ │ (浏览器聊天界面) │ └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ Nginx :8001 │ │ (least_conn 负载均衡) │ └────┬────────────┬─────┘ │ │ ┌────────▼───┐ ┌────▼───────┐ │ 实例1 :8002 │ │ 实例2 :8003 │ │ 卡 0~3 │ │ 卡 4~7 │ │ NUMA 节点3 │ │ NUMA 节点7 │ │ TP=4 │ │ TP=4 │ └────────────┘ └────────────┘ ``` ---
全部评论(3)
只看楼主
C
CrystalRays
2楼
双卡部署awq实测能到30+tok/s
5/29
小
小鱼
1楼
请问这套方案用来几人小团队编程怎么样?
5/28
Z
zhangjing
回复 @小鱼
10个人左右这样
6/8
没有更多内容了
--
楼主
Level.3
0 帖子
楼主热帖
暂无数据