3
Qwen
新人贴
Qwen3.5-122B-A10B,vLLM,K100两台,16卡张量并行,128K上下文,推理性能实测。
2026-06-30 17:05:53
415
# Qwen3.5-122B-A10B vLLM 多机多卡部署文档 ## 一、环境说明 | 项目 | 节点1 | 节点2 | |------|-------|-------| | IP | 10.1.1.1 | 10.1.1.2 | | GPU | 8x DCU | 8x DCU | | NUMA | 0-7 | 8-15 | | 网络 | bond1 | bond1 | | 总 GPU | 16 张 | TP=16 | - **镜像**: `harbor.sourcefind.cn:5443/dcu/admin/base/custom:vllm018-ubuntu22.04-dtk26.04-gemma4-0413` - **vLLM**: 0.18.1 | **模型**: Qwen3.5-122B-A10B | **框架**: Ray --- ## 二、Docker Compose 启动前看卡在不hy-smi ![1782809466637.png](/api-forum/file/RedirectImage?path=20260630/1782809467160_1782809466637.png '1782809466637.png') ```yaml version: "3.8" services: vllm: image: harbor.sourcefind.cn:5443/dcu/admin/base/custom:vllm018-ubuntu22.04-dtk26.04-gemma4-0413 container_name: vllm stdin_open: true tty: true shm_size: "200" network_mode: host privileged: true devices: - /dev/kfd - /dev/dri - /dev/mkfd group_add: - video cap_add: - SYS_PTRACE security_opt: - seccomp=unconfined user: root volumes: - /opt/hyhal/:/opt/hyhal/:ro - /data/models:/models command: bash ``` 进容器: `docker exec -it vllm /bin/bash` --- ## 三、环境变量 查看网卡速率 ethtool bond1 | grep -E "Speed|Duplex" ethtool bond0 | grep -E "Speed|Duplex" ethtool ens2f0np0 | grep -E "Speed|Duplex" ![1782889524296.png](/api-forum/file/RedirectImage?path=20260701/1782889524491_1782889524296.jpg '1782889524296.png') ![1782809341930.png](/api-forum/file/RedirectImage?path=20260630/1782809342509_1782809341930.jpg '1782809341930.png') ### 节点1 ```bash export ALLREDUCE_STREAM_WITH_COMPUTE=1 export VLLM_HOST_IP=10.1.1.1 export NCCL_SOCKET_IFNAME=ens2f0np0 export GLOO_SOCKET_IFNAME=ens2f0np0 unset NCCL_ALGO export NCCL_MIN_NCHANNELS=16 export NCCL_MAX_NCHANNELS=16 export NCCL_NET_GDR_READ=0 export NCCL_NET_GDR_LEVEL=0 export NCCL_IB_DISABLE=1 export HIP_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 export VLLM_RPC_TIMEOUT=1800000 export VLLM_USE_V1=0 export VLLM_NUMA_BIND=1 export VLLM_RANK0_NUMA=0 export VLLM_RANK1_NUMA=1 export VLLM_RANK2_NUMA=2 export VLLM_RANK3_NUMA=3 export VLLM_RANK4_NUMA=4 export VLLM_RANK5_NUMA=5 export VLLM_RANK6_NUMA=6 export VLLM_RANK7_NUMA=7 ``` ### 节点2 ```bash export ALLREDUCE_STREAM_WITH_COMPUTE=1 export VLLM_HOST_IP=10.1.1.2 export NCCL_SOCKET_IFNAME=ens2f0np0 export GLOO_SOCKET_IFNAME=ens2f0np0 unset NCCL_ALGO export NCCL_MIN_NCHANNELS=16 export NCCL_MAX_NCHANNELS=16 export NCCL_NET_GDR_READ=0 export NCCL_NET_GDR_LEVEL=0 export NCCL_IB_DISABLE=1 export HIP_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 export VLLM_RPC_TIMEOUT=1800000 export VLLM_USE_V1=0 export VLLM_NUMA_BIND=1 export VLLM_RANK0_NUMA=8 export VLLM_RANK1_NUMA=9 export VLLM_RANK2_NUMA=10 export VLLM_RANK3_NUMA=11 export VLLM_RANK4_NUMA=12 export VLLM_RANK5_NUMA=13 export VLLM_RANK6_NUMA=14 export VLLM_RANK7_NUMA=15 ``` > **⚠️ 节点2 HIP_VISIBLE_DEVICES=0-7,不是8-15。rocm-smi验证。** --- ## 四、Ray 集群 ```bash # 节点1 ray start --head --node-ip-address=10.1.1.1 --port=6379 --num-gpus=8 --num-cpus=32 # 节点2 ray start --address='10.1.1.1:6379' --num-gpus=8 --num-cpus=32 # 验证 ray status ray list nodes echo $HIP_VISIBLE_DEVICES # 清理 #ray stop #pkill -f vllm #pkill -f ray ``` --- ## 五、启动 vLLM ```bash export VLLM_USE_V1=0 vllm serve /models/Qwen3.5-122B-A10B \ --host 0.0.0.0 \ --port 1025 \ --served-model-name Qwen3.5-122B-A10B \ --tensor-parallel-size 16 \ --max-model-len 128000 \ --gpu-memory-utilization 0.9 \ --distributed-executor-backend ray \ >> ./vllm_serve.log 2>&1 & tail -f vllm_serve.log # 验证 curl localhost:1025/v1/models ``` ![1782810085892.png](/api-forum/file/RedirectImage?path=20260630/1782810086595_1782810085892.jpg '1782810085892.png') --- ## 六、测试脚本 ### test.py(流式输出) ```python #!/usr/bin/env python3 # -*- coding: utf-8 -*- import time import json import requests URL = "http://localhost:1025/v1/chat/completions" MODEL = "Qwen3.5-122B-A10B" print("=== vLLM 流式性能测试 ===") while True: prompt = input("\n你:") if prompt.lower() in ("exit", "quit"): break payload = { "model": MODEL, "messages": [{"role": "user", "content": prompt}], "max_tokens": 3000, "temperature": 0.7, "stream": True } start_time = time.time() first_token_time = None char_count = 0 print("模型回答:", end="", flush=True) with requests.post(URL, json=payload, stream=True, timeout=300) as r: r.raise_for_status() for raw_line in r.iter_lines(): if not raw_line: continue line = raw_line.decode("utf-8").strip() if not line.startswith("data:"): continue data = line[5:].strip() if data == "[DONE]": break try: obj = json.loads(data) delta = obj["choices"][0]["delta"] content = ( delta.get("content") or delta.get("reasoning_content") or "" ) if content: if first_token_time is None: first_token_time = time.time() - start_time print(content, end="", flush=True) char_count += len(content) except Exception: continue total_time = time.time() - start_time est_tokens = int(char_count / 1.4) if char_count else 0 tps = est_tokens / total_time if total_time > 0 else 0 print("\n----------------------------------------") if first_token_time is not None: print(f"首字延迟 TTFT : {first_token_time:.3f} 秒") else: print("首字延迟 TTFT : 未收到响应") print(f"响应字符数 : {char_count}") print(f"估算 Token 数 : {est_tokens}") print(f"总耗时 : {total_time:.3f} 秒") print(f"生成速度 TPS : {tps:.2f} tokens/s") print("----------------------------------------") ``` ![1782810198805.png](/api-forum/file/RedirectImage?path=20260630/1782810199345_1782810198805.png '1782810198805.png') --- ### test-context.py(长上下文测试) ```python #!/usr/bin/env python3 import time, json, requests URL = "http://localhost:1025/v1/chat/completions" MODEL = "Qwen3.5-122B-A10B" START_TOKENS = 20480 STEP_TOKENS = 20480 MAX_ATTEMPTS = 100 BASE_TEXT = ( "人工智能是计算机科学的一个分支,它企图了解智能的实质..." ) def generate_long_text(target_tokens): target_chars = int(target_tokens * 1.5) repeat_times = max(1, target_chars // len(BASE_TEXT)) return BASE_TEXT * repeat_times print("=== vLLM 最大上下文窗口测试 ===") current_tokens = START_TOKENS successful_tokens = 0 for attempt in range(MAX_ATTEMPTS): print(f"[测试 #{attempt+1}] {current_tokens} tokens...") long_prompt = generate_long_text(current_tokens) payload = { "model": MODEL, "messages": [ {"role": "system", "content": "你是一个有用的助手。"}, {"role": "user", "content": long_prompt + " 请总结上文核心观点。"} ], "max_tokens": 10, "temperature": 0.0, "stream": False } start = time.time() try: r = requests.post(URL, json=payload, timeout=120) elapsed = time.time() - start if r.status_code == 400: print(f"❌ 触发上下文限制。上限: {successful_tokens}") break r.raise_for_status() successful_tokens = current_tokens print(f"✅ 成功!耗时: {elapsed:.2f}s") current_tokens += STEP_TOKENS time.sleep(1) except Exception as e: print(f"❌ 错误: {e}") break print(f"最终结果: 支持的最大输入 Token 数约为 {successful_tokens}") ``` ![1782810221892.png](/api-forum/file/RedirectImage?path=20260630/1782810222470_1782810221892.jpg '1782810221892.png') ### test-all.py(并发压测) ```python #!/usr/bin/env python3 import time, json, statistics, threading, requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry URL = "http://localhost:1025/v1/chat/completions" MODEL = "Qwen3.5-122B-A10B" ROUNDS = 3 CONCURRENT = 264 MAX_TOKENS = 1024 TEMPERATURE = 0.7 PROMPT = "请用非常详细的篇幅介绍人工智能的发展历史..." ttft_list, tps_list = [], [] success_cnt = 0 lock = threading.Lock() def get_session(): s = requests.Session() adapter = HTTPAdapter(pool_connections=CONCURRENT, pool_maxsize=CONCURRENT, max_retries=Retry(total=0)) s.mount("http://", adapter) return s def worker(tid, session): global success_cnt for i in range(ROUNDS): payload = { "model": MODEL, "messages": [{"role": "user", "content": PROMPT}], "max_tokens": MAX_TOKENS, "temperature": TEMPERATURE, "stream": True } start = time.time() ttft, chars = None, 0 try: with session.post(URL, json=payload, stream=True, timeout=600) as r: r.raise_for_status() for line in r.iter_lines(chunk_size=512): if not line or not line.startswith(b"data:"): continue data = line[5:].strip() if data == b"[DONE]": break obj = json.loads(data) content = obj["choices"][0]["delta"].get("content") or "" if content: if ttft is None: ttft = time.time() - start chars += len(content) except Exception as e: print(f"[线程 {tid}] 出错: {e}") continue total = time.time() - start est_tokens = int(chars / 1.4) tps = est_tokens / total if total > 0 else 0 with lock: if ttft and est_tokens > 0: ttft_list.append(ttft) tps_list.append(tps) success_cnt += 1 print(f"[线程{tid} 第{i+1}轮] TTFT:{ttft:.3f}s TPS:{tps:.2f}") print(f"=== 并发压测 (并发={CONCURRENT}, 轮次={ROUNDS}) ===") session = get_session() threads = [threading.Thread(target=worker, args=(tid+1, session)) for tid in range(CONCURRENT)] for t in threads: t.start() for t in threads: t.join() print(" =========== 压测汇总 ===========") print(f"成功请求: {success_cnt}") if ttft_list: print(f"TTFT 均值: {statistics.mean(ttft_list):.3f}s 最小:{min(ttft_list):.3f}s 最大:{max(ttft_list):.3f}s") print(f"TPS 均值: {statistics.mean(tps_list):.2f} 最小:{min(tps_list):.2f} 最大:{max(tps_list):.2f}") ``` --- ![1782810266080.png](/api-forum/file/RedirectImage?path=20260630/1782810266666_1782810266080.jpg '1782810266080.png')
全部评论(4)
只看楼主
刘
刘
楼主
1楼
小白目前也不知道还有什么需要优化的,有大神的话讨论一下
6/30
叫
叫我小王
回复 @刘
请问 8张 k100 可以吗

7/3
刘
刘
回复 @叫我小王
可以的 token40-50左右 我思考关闭了的
  vllm serve /models/Qwen3.5-122B-A10B \
  --host 0.0.0.0 \
  --port 1026 \
  --served-model-name Qwen3.5-122B-A10B \
  --tensor-parallel-size 8 \
  --trust-remote-code \
  --dtype float16 \
  --max-model-len 128000 \
  --max-num-seqs 32 \
  --max-num-batched-tokens 131072 \
  --enable-chunked-prefill \
  --enable-prefix-caching \
  --block-size 16 \
  --max-log-len 1024 \
  --gpu-memory-utilization 0.95 \
  --reasoning-parser qwen3 \
  --default-chat-template-kwargs '{"enable_thinking": false}' \
  >> ./vllm_a.log 2>&1 &
7/3
刘
刘
回复 @叫我小王
attachmentId-image.png5并发 速度会变慢 我这个是双台均衡的 应该在单条5并发 token30不到 并发再高就10左右了
7/3
没有更多内容了
--
楼主
Level.6
0 帖子
楼主热帖
暂无数据