部署基于SGLang的Qwen3-32B多机推理服务
本文以Qwen3-32B模型为例,演示如何在CCE中使用SGLang部署多机推理服务。
背景知识
- Qwen3-32B
Qwen3-32B 是通义千问系列最新一代的大型语言模型,基于328亿参数的密集模型架构,兼具卓越的推理能力与高效的对话性能。其最大特色在于支持思考模式与非思考模式的无缝切换。在复杂逻辑推理、数学计算和代码生成任务中表现出众,而在日常对话场景下也可高效响应。模型具备出色的指令遵循、多轮对话、角色扮演和创意写作能力,并在Agent任务中实现领先的工具调用表现。原生支持32K上下文,结合YaRN技术可扩展至131K。同时,支持100多种语言,具备强大的多语言理解与翻译能力,适用于全球化应用场景。有关更多详细信息,请参阅博客、GitHub和文档。
- SGLang
SGLang 是一个高性能的大型语言模型与多模态模型服务推理引擎,通过前后端协同设计,提升模型交互速度与控制能力。其后端支持 RadixAttention(前缀缓存)、零开销 CPU 调度、PD分离、Speculative decoding、连续批处理、PagedAttention、TP/DP/PP/EP并行、结构化输出、chunked prefill及多种量化技术(FP8/INT4/AWQ/GPTQ)和多LoRA批处理,显著提升推理效率。前端提供灵活编程接口,支持链式生成、高级提示、控制流、多模态输入、并行处理和外部交互,便于构建复杂应用。支持 Qwen、DeepSeek、Llama等生成模型,E5-Mistral等嵌入模型以及 Skywork 等奖励模型,易于扩展新模型。更多关于SGLang推理引擎的信息,请参见SGLang GitHub。
- 多机分布式部署
随着大语言模型(LLM)参数规模的不断增长,单个GPU已无法承载完整模型。多机分布式部署通过并行策略将庞大的推理任务拆分成多个子任务,分配给多个GPU计算单元并行处理,最后高效汇总结果,从而实现大模型的快速推理。
核心并行策略有以下4种:
11. 数据并行(DP):每个GPU持有完整模型副本,但处理不同的数据批次,适合提升吞吐量。
22. 张量并行(TP):将模型权重切分到多个GPU,每个GPU只加载和计算部分权重,适合超大模型的单层计算加速。
33. 流水线并行(PP):按模型层分配GPU,像流水线一样逐层传递中间结果,适合深层模型的内存优化。
44. 专家并行(EP):针对MoE架构,将不同专家模型分布到多个GPU,按需路由激活,提升稀疏模型效率。
前提条件
- 已创建CCE集群且集群版本为1.31及以上,并且已经为集群添加GPU节点。
具体操作,请参见创建CCE托管集群。
本文要求GPU显存需大于64GB,推荐使用bcc.lsgn7ec.c176m1952.8h20-141.2d规格(请联系客户经理申请GPU规格邀测)。
- 已安装RoleBasedGroup。安装方法:在CCE控制台,进入Helm模版,选择社区模版-rbgs,点击安装。选择已有集群进行安装。
模型部署
步骤一:准备Qwen3-32B模型文件
- 执行以下命令从ModelScope下载Qwen-32B模型。
请确认是否已安装git-lfs插件,如未安装可执行
yum install git-lfs或者apt-get install git-lfs安装。更多的安装方式,请参见安装git-lfs。
1git lfs install
2GIT_LFS_SKIP_SMUDGE=1 git clone https://www.modelscope.cn/Qwen/Qwen3-32B.git
3cd Qwen3-32B/
4git lfs pull
- 登录PFS控制台,将集群中的节点挂载到PFS挂载服务中,参考控制台操作文档和命令行操作文档。如何创建PFS文件系统,创建挂载服务并绑定存储实例,请参考创建文件系统,创建挂载服务,绑定存储实例。
- 在PFS中创建目录,将模型拷贝到PFS中。
1mkdir Qwen-models
2cp /Qwen3-32B/ <pfs目录>/Qwen-models/
- 创建PV和PVC。为目标集群配置存储卷PV和存储声明PVC。请参考使用并行文件存储PFS L2。
- 通过Yaml新建PV示例:
1apiVersion: v1
2kind: PersistentVolume
3metadata:
4 name: <your-pv-name> #本示例中为test-pv-02
5spec:
6 accessModes:
7 - ReadOnlyMany
8 capacity:
9 storage: 500Gi
10 local:
11 path: <your-pfs-path> #本示例中为/pfs/pfs-qnL8Jh/Qwen-models
12 nodeAffinity:
13 required:
14 nodeSelectorTerms:
15 - matchExpressions:
16 - key: ready-for-pfsl2
17 operator: In
18 values:
19 - "true"
20 persistentVolumeReclaimPolicy: Retain
21 storageClassName: local-volume
22 volumeMode: Filesystem
- 通过Yaml新建PVC示例:
1apiVersion: v1
2kind: PersistentVolumeClaim
3metadata:
4 finalizers:
5 - kubernetes.io/pvc-protection
6 name: <your-pvc-name> #本示例中为test-pvc-02
7 namespace: default
8spec:
9 accessModes:
10 - ReadOnlyMany
11 resources:
12 requests:
13 storage: 500Gi
14 storageClassName: local-volume
15 volumeMode: Filesystem
16 volumeName: <your-pv-name> #本示例中为test-pv-02
步骤二:部署推理服务
- 创建 qwen3-32B-2worker.yaml 文件
1apiVersion: workloads.x-k8s.io/v1alpha1
2kind: RoleBasedGroup
3metadata:
4 name: sglang-qwen3-32b-2worker
5spec:
6 roles:
7 - name: scheduler
8 replicas: 1
9 template:
10 spec:
11 serviceAccountName: sglang-router-sa
12 volumes:
13 - name: model
14 persistentVolumeClaim:
15 claimName: <your-pvc-name>
16 containers:
17 - name: scheduler
18 image: registry.baidubce.com/ai-native-dev/infer-manager/dev-image:0.4.ubuntu2204-py313-sglang0.5.2-router0.1.9-mooncake-0.3.6-nixl-0.6.0-cuda12.4
19 command:
20 - sh
21 - -c
22 - |
23 python -m sglang_router.launch_router \
24 --service-discovery \
25 --service-discovery-namespace default \
26 --selector "baidu-cce/inference-workload=sglang-qwen3-32b-worker" \
27 --policy round_robin \
28 --service-discovery-port 8000 \
29 --host 0.0.0.0 \
30 --port 8000
31 volumeMounts:
32 - mountPath: /models
33 name: model
34
35 - name: worker
36 replicas: 2
37 template:
38 metadata:
39 labels:
40 baidu-cce/inference-workload: sglang-qwen3-32b-worker
41 baidu-cce/inference_backend: sglang
42 spec:
43 serviceAccountName: sglang-router-sa
44 nodeSelector:
45 gputype: h20
46 volumes:
47 - name: model
48 persistentVolumeClaim:
49 claimName: <your-pvc-name>
50 - name: dshm
51 emptyDir:
52 medium: Memory
53 sizeLimit: 15Gi
54 containers:
55 - name: sglang-worker
56 image: registry.baidubce.com/ai-native-dev/infer-manager/dev-image:0.4.ubuntu2204-py313-sglang0.5.2-router0.1.9-mooncake-0.3.6-nixl-0.6.0-cuda12.4
57 imagePullPolicy: Always
58 env:
59 - name: POD_IP
60 valueFrom:
61 fieldRef:
62 fieldPath: status.podIP
63 command:
64 - sh
65 - -c
66 - |
67 ldconfig
68 PYTHONPATH=/workspace/github.com/sglang/python:$PYTHONPATH \
69 python -m sglang.launch_server \
70 --tp 2 \
71 --model-path /<your-model-path>/ \
72 --port 8000 \
73 --host $(POD_IP) \
74 --enable-metrics
75 ports:
76 - containerPort: 8000
77 name: http
78 readinessProbe:
79 initialDelaySeconds: 30
80 periodSeconds: 10
81 tcpSocket:
82 port: 8000
83 resources:
84 limits:
85 nvidia.com/gpu: "2"
86 memory: "256Gi"
87 cpu: "32"
88 requests:
89 nvidia.com/gpu: "2"
90 memory: "256Gi"
91 cpu: "32"
92 volumeMounts:
93 - mountPath: /models
94 name: model
95 - mountPath: /dev/shm
96 name: dshm
- 部署SGLang Qwen3-32B推理服务。
1kubectl create -f qwen3-32B-2worker.yaml
步骤三:验证推理服务
- 获取scheduler pod ip,执行以下命令,向模型推理服务发送一条示例的模型推理请求。
1curl http://<your-scheduler-pod-ip>:8000/v1/chat/completions -H "Content-Type: application/json" -d '{"model": "models/Qwen/Qwen3-32B", "messages": [{"role": "user", "content": "测试一下,用python代码写出hello world"}], "max_tokens": 2000, "temperature": 0.7, "top_p": 0.9, "seed": 10}'
预期输出:
1{"id":"36ad9b618c3943e2a5db7eaf53656445","object":"chat.completion","created":1760585450,"model":"/Qwen-models/Qwen3-32B","choices":[{"index":0,"message":{"role":"assistant","content":"<think>\n嗯,用户让我测试一下,用Python代码写一个Hello World。首先,我需要确认用户的需求是什么。他们可能是一个刚开始学编程的新手,想看看最基础的例子。或者他们可能是在验证Python环境是否安装正确,或者想测试代码执行的效果。\n\n首先,我应该回忆一下Python中如何输出Hello World。最简单的方法是用print函数,对吧?比如print(\"Hello World\")。这个应该就能运行了。不过用户可能需要更多的细节,比如解释代码的结构,或者如何运行这段代码。\n\n接下来,我需要考虑用户可能的背景。如果是完全的新手,可能需要更详细的步骤,比如如何保存文件,如何运行脚本。或者他们可能只需要代码,不需要额外的解释。这时候可能需要判断用户的意图。\n\n另外,用户提到“测试一下”,可能他们想确认代码是否正确,或者他们自己的环境是否正常。这时候,除了提供代码,可能还需要指出常见的错误,比如拼写错误,或者忘记引号之类的。\n\n还有可能用户希望看到不同的方式来实现Hello World,比如使用函数或者类,不过一般来说最简单的print语句就够了。不过可能需要确认用户是否想要更复杂的例子,但通常新手只需要最基础的。\n\n然后,我需要检查自己给出的代码是否正确。比如,print(\"Hello World\")是否正确,有没有语法错误。比如括号是否正确,引号是否闭合。Python 3中print是一个函数,所以必须用括号,而Python 2可能用print \"Hello World\",但用户可能使用的是Python 3,所以应该用函数形式。\n\n另外,可能需要提醒用户注意大小写和空格,比如H是大写,后面有空格,以及标点符号是否正确。比如用户是否想输出“Hello, World!”,但根据问题中的“hello world”,可能不需要标点,但有时候常见的例子是带感叹号的。不过用户给出的例子是“hello world”,所以应该按照用户的要求来写,不加标点。\n\n总结一下,用户的需求应该是得到一个正确的Python代码示例,能够输出指定的字符串。可能需要确认代码的正确性,以及如何运行。作为回答,我应该提供最简单的代码,并可能附上简短的说明,比如解释print函数的作用,以及如何执行脚本。如果用户需要更详细的步骤,可能需要进一步询问,但根据当前的问题,可能只需要给出代码即可。\n</think>\n\n以下是一个简单的 Python 代码示例,用于输出 \"hello world\":\n\n```python\nprint(\"hello world\")\n```\n\n### 说明:\n- `print()` 是 Python 的内置函数,用于将括号内的内容输出到控制台。\n- 字符串 `\"hello world\"` 被作为参数传递给 `print()` 函数。\n- 代码运行后,控制台将显示 `hello world`。\n\n### 如何运行:\n1. 将代码保存为文件,例如 `hello.py`。\n2. 在终端/命令行中运行:`python hello.py`。\n3. 或在支持 Python 的在线编辑器(如 [Replit](https://replit.com/))中直接执行。\n\n### 输出结果:\n```\nhello world\n```\n\n这是 Python 编程中最基础的入门示例,常用于验证开发环境是否配置正确。","reasoning_content":null,"tool_calls":null},"logprobs":null,"finish_reason":"stop","matched_stop":151645}],"usage":{"prompt_tokens":17,"total_tokens":709,"completion_tokens":692,"prompt_tokens_details":null,"reasoning_tokens":0},"metadata":{"weight_version":"default"}}
输出结果表明模型可以根据给定的输入(在这个例子中是一条测试消息,用python代码写出hello world)生成相应的回复。
