最近大模型落地这块,国产算力的存在感越来越强。我这边从去年开始就在搞海光 DCU 怎么接入 Kubernetes,一开始以为把 NVIDIA 那套 device plugin 换皮就能用,结果从驱动到调度器再到推理框架,几乎每个环节都踩了坑。这篇文章把 CubeStudio、Kubernetes、vDCU 虚拟化以及 DeepSeek 部署这条链路完整梳理一遍,既是给自己做个记录,也给准备在 DCU 上做集群化和模型服务的同学一份可以直接照着抄的实操参考。
内容适合谁:已经在用或准备用 DCU 做训练/推理的运维和算法同学;手里有 K8s 集群想接国产加速卡的平台工程师;以及想在 DCU 上跑 DeepSeek 但不知道从哪下手的人。下面我尽量按"原理 → 配置 → 踩坑"的顺序来讲,命令和 yaml 都是我们在生产环境验证过的版本,可以直接改着用。
1. 为什么海光 DCU 上 K8s 这件事值得单独写一篇
1.1 先分清 DCU 到底是个什么角色
海光 DCU(Deep Computing Unit)从硬件架构上讲,走的是类 CDNA 的路线,生态上兼容 HIP/ROCm。这句"兼容"很重要,它决定了你后面所有软件选型的方向:不能再用 CUDA 的思维方式,而是要切换到 HIP 的语境下。对很多团队来说,最难接受的不是性能数字,而是心智模型的转变。
我们有几台 64GB 显存的 DCU 卡,单卡能装下 7B~14B 的模型,如果做量化,32B 也有机会。这个规格其实已经覆盖了相当大一部分企业级推理场景。所以从业务需求出发,DCU 不是"能不能用"的问题,而是"怎么用好"的问题。
1.2 直接照搬 NVIDIA 方案为什么不行
NVIDIA 在 K8s 里靠三件套:device plugin、容器运行时插件、以及 CUDA 生态里的各类 operator。这三件套任意一件都假设了设备厂商是 NVIDIA。DCU 对应的替代品是海光自己的 device plugin、容器运行时和 DTK 工具链。名字听起来像,但接口、配置项、上报的资源名都不一样。
而且有一个特别容易踩的坑:NVIDIA 的 device plugin 上报的资源名是 nvidia.com/gpu,而 DCU 的 device plugin 默认上报的是 hygon.com/dcu 这类自定义扩展资源。K8s 调度器对扩展资源只做"整数数量"的匹配,不做显存、拓扑、卡上任务的感知,这意味着你必须额外想办法把"显存大小""卡间拓扑""虚拟化粒度"这些信息带进调度决策里,否则 Pod 能不能起来完全是运气。
1.3 这篇文章解决的问题范围
我不会展开讲 DCU 驱动怎么安装(这个官方文档写得很清楚),重点放在三块:一是 DCU 正确接入 K8s 的基础设施链路,二是 CubeStudio 这类 AI 平台在中间帮我们解决了什么、没解决什么,三是 vDCU 的两种虚拟化模式怎么选,以及怎么在 DCU 上把 DeepSeek 跑起来。看完你应该能回答"我的业务到底该用整卡、共享还是 vDCU"这个问题。
2. 搞懂 DCU 软件栈是适配的地基:DTK、HIP 与容器运行时
2.1 DTK 版本和驱动对应关系
DTK(DCU Toolkit)是海光在 ROCm 生态上封装的一整套开发套件,里面有 HIP 编译器、MIOpen-DCU(算子库)、HiCCL(集合通信库)等等。第一次接触的人最容易犯的错,是以为 DTK 只是一个"装完就完事"的 SDK。实际上 DTK 的版本必须和驱动版本、PyTorch 版本严格对齐,否则你会看到编译能过、算子却全部回退到 CPU 的诡异现象——因为 HIP runtime 和 kernel 版本不匹配时,很多算子会静默降级。
我建议把版本对齐当成第一优先级:先确定驱动版本,再选对应 DTK,然后才谈镜像。官方镜像的 tag 通常会写明 dtk 和 pytorch 的版本组合,比如 pytorch:2.1.0-dtk24.04-py3.10,这种 tag 策略能省掉你一半以上的环境问题。
注意:DCU 容器镜像里一定要保留 /opt/dtk 这个路径,很多框架在容器里会硬编码找它。你自定义镜像的时候如果在精简阶段把这个目录删了,运行时会报"cannot find libamdhip64"这类错误,非常隐蔽。
2.2 为容器运行时装好"眼睛和手脚"
K8s 要调度 DCU,节点上必须有三个东西:驱动、容器运行时插件、device plugin。驱动提供设备节点 /dev/dcu0 这类文件;容器运行时插件负责在容器启动时把设备文件、驱动库、权限注入容器;device plugin 负责把设备数量上报给 kubelet,让 K8s 认为节点上存在"hygon.com/dcu"这种资源。
其中容器运行时插件是最容易被忽略的一环。很多人以为装了 device plugin 就能用,结果 Pod 里看不到设备,就是因为容器运行时没有注入设备。以 Docker 为例,需要在 /etc/docker/daemon.json 里配置 runtime 指向 DCU 的 runtime 可执行文件,然后重启 docker 和 kubelet。如果你用的 containerd,则在 /etc/containerd/config.toml 里加对应的 runtime 配置。
2.3 最小验证清单
我建议在正式接入 K8s 之前,先在单机上用 docker 手动跑一个容器验证:
docker run --rm \ --device=/dev/dcu0 \ --security-opt seccomp=unconfined \ -e HIP_VISIBLE_DEVICES=0 \ hub.example.com/dcu/pytorch:2.1.0-dtk24.04-py3.10 \ sh -c "dcu-smi && hipcc --version"能看到类似驱动版本、显存总量、HIP 编译器版本信息,说明驱动和运行时没问题;再看 device plugin 上报数量,才轮到 K8s 层的问题。这个顺序很重要——先把底层链路打穿,不要一上来就在 K8s 里排查。
3. CubeStudio 在整套体系里扮演什么角色
3.1 CubeStudio 是什么
CubeStudio 是我这边选型下来的一站式 AI 平台,底层还是 Kubernetes,只不过它把 K8s 那套资源抽象、调度、配额、多租户功能做了产品化封装,对外提供的是"开发训练推理一体"的界面和 API。用户不需要直接写 Deployment 去申请 DCU,而是在平台里创建开发环境、提交训练任务、上线推理服务,平台负责把这些请求翻译成 K8s 对象。
对我们做平台的人来说,选 CubeStudio 而不是自己基于原生 K8s 一点一点搭,最大的收益是省掉了三块重复劳动:资源配额和租户隔离、任务生命周期管理(排队、重试、日志、指标)、以及加速卡资源的上报与展示。这些功能自己写不是不行,但每一条都对应着一堆边缘情况,性价比很低。
3.2 CubeStudio 与 K8s、DCU 的联动方式
CubeStudio 不会重复造 device plugin 的轮子,它默认还是走"节点有 DCU 资源 → 平台在上层做调度"的路线。资源上报依旧靠我们部署的 DCU device plugin,CubeStudio 只是读取节点 capacity 和 allocatable,并在创建任务时帮你注入对应的 resource request/limit。
不过要注意一个细节:CubeStudio 这类平台的调度器通常只认资源数量,不认显存和卡型。如果你集群里混着不同显存大小的 DCU,它可能把 7B 模型的任务调度到显存不够的节点上。我们的做法是在 CubeStudio 里用"资源模板/机型"的概念隔离卡型,把相同显存的节点放进同一个池子,再把模型所需的最小显存做成模板参数。这一层经验一定要提前设计,别等节点多了再后悔。
3.3 CubeStudio 里跑通第一个 DCU 任务
以我们环境为例,在 CubeStudio 里创建一个 PyTorch 开发环境时,需要选三样东西:镜像(带 DTK 的)、资源规格(几卡、多少 CPU/内存)、以及启动命令。平台背后生成的是一个带有 resource limits 的 Pod,我们只要确认 Pod 里能跑通 dcu-smi 就算成功。这里有个坑:如果平台默认给的 Pod 模板不带 DCU 的资源请求,就算节点有卡也不会注入,必须先确认平台的"资源规格"配置里有 hygon.com/dcu 这个自定义资源。
4. 整卡接入:Device Plugin + 调度器的改造
4.1 整卡模式下的资源模型
整卡模式最简单:一张 DCU 卡只能被一个 Pod 独占。device plugin 把每张物理卡上报为一个"hygon.com/dcu"资源单位,用户申请 1 就是独占一张,申请 2 就是独占两张。这种模式的优点是隔离彻底、行为可预期、适合大模型训练和需要确定性性能的推理;缺点是碎片化严重——一张 64GB 卡跑个 7B 模型可能只用了 20GB,剩下的 40GB 谁也碰不到。
4.2 Device Plugin 上报的工作原理
Device Plugin 是 K8s 的一组标准插件接口:插件启动后通过 ListAndWatch 向 kubelet 提供设备列表,kubelet 将这些设备作为扩展资源公布到节点状态上。调度器看到节点 capacity 里有 hygon.com/dcu: 4,就知道这台机器有 4 张 DCU。Pod 调度后,kubelet 会调用插件的 Allocate 接口,由插件决定给容器注入哪些设备文件和环境变量。
官方或社区常见的 DCU device plugin 支持环境变量配置文件,比如通过环境变量控制 HIP 相关参数,也支持在 Allocate 阶段设置 HIP_VISIBLE_DEVICES,保证每个容器只能看到自己申请的那张卡。这个隔离依赖的正是 HIP_VISIBLE_DEVICES 的注入,检查 Pod 环境变量是你排查"容器里看到所有卡"问题的第一步。
4.3 裸 K8s 下整卡调度的 yaml
一条最朴素的 DCU Pod 大概长这样(直接用原生 K8s 发布的方式):
apiVersion: v1 kind: Pod metadata: name: dcu-whole-card-demo spec: restartPolicy: Never containers: - name: pytorch-dcu image: hub.example.com/dcu/pytorch:2.1.0-dtk24.04-py3.10 command: ["sh", "-c"] args: - | dcu-smi hipcc --version sleep infinity resources: limits: hygon.com/dcu: 1一个关键点必须说清楚:K8s 原生调度器对自定义扩展资源只支持"按整数数量调度",它不知道"这张卡还剩多少显存"。所以上面这个 yaml 里虽然申请了 1 张卡,但如果同一台节点上已经有其他 Pod 占用了这张卡(共享模式),原生调度器是感知不到的,这就需要 vDCU 或调度器扩展来兜底,具体后面两章展开。
4.4 验证整卡是否真的"隔离"
Pod 起来后,进容器执行 dcu-smi,如果环境变量隔离生效,你应该只能看到 1 张卡,编号从 0 开始,和宿主机的物理卡号无关。这一步验证通过,才说明 device plugin 的 Allocate 阶段工作正常。
5. 共享模式:一张卡上跑多个 Pod 的折中方案
5.1 共享的收益与代价
整卡独占的资源浪费在推理场景尤其明显。很多小而多的推理任务(比如一批轻量 embedding 服务、多个小模型的灰度版本)显存只用到 10GB 左右,却要占一整张 64GB 的卡。共享模式就是为了解决这种"大卡小任务"的错配:一张物理卡拆成多个逻辑设备,每个 Pod 申请其中一个逻辑设备。
代价是共享会引入性能和稳定性的不确定性。多个容器共享一张卡,HBM 带宽和算力是竞争关系,一个跑满算力的任务会把同卡其他任务的延迟拉高。所以共享模式绝不是"免费的弹性",它适合负载峰谷明显的场景,不适合所有任务都混在一起跑。
5.2 共享模式怎么实现
共享模式的实现关键在 device plugin:通过配置把每张物理卡暴露成多个副本。比如你希望一张卡最多同时跑到 4 个容器,就把 plugin 配置里的副本数设置为 4,plugin 会向 kubelet 上报 hygon.com/dcu: 4×N。每个容器申请 1 个,实际拿到的还是同一张物理卡,只是 plugin 保证"这张卡上同时运行的容器数不超过 4"。
注意共享模式下 device plugin 往往也需要注入不同的 HIP_VISIBLE_DEVICES,但物理卡只有一张,所以真正隔离的是"并发数"而不是"显存"。假如三个容器各占了 20GB 显存,这张卡只有 64GB,剩下的 4GB 一旦再有任务申请就会直接 OOM。设备插件通常不感知显存分配,这属于共享模式和 vDCU 最本质的差异。
5.3 共享模式最适合的落地场景
我们用下来的体会是,共享模式最适合两类任务:一类是开发调试和 notebook,占着卡跑交互式代码,负荷低但需要快速响应;另一类是轻量推理服务,模型小、吞吐有限、对偶尔的延迟抖动不敏感。训练任务尽量不要放共享卡上,反向传播的显存占用峰值很难预测,万一 OOM 把整张卡上其他任务都拖下水,这种事故我们出过一次之后就再也没敢混过。
6. vDCU 虚拟化:两条路线怎么选
vDCU 是解决"共享"痛点更系统的方式。它和前面说的"共享模式"的区别是:共享模式只做一个"并发计数 + 环境变量注入",而 vDCU 是驱动层面真正把一张 DCU 虚拟化出多个逻辑 DCU 设备,每个逻辑设备有自己的显存视图和算力配额。目前我们实际用到的 vDCU 分两种,侧重点完全不同。
6.1 时间片型 vDCU
时间片型 vDCU 的思路是:多个逻辑设备共享同一张物理卡的算力,由驱动按时间片轮转调度,每个逻辑设备拥有独立的显存地址空间视图,但显存总容量仍然是共享的。它适合的应用画像和共享模式很像,但隔离性更好:任务之间不会互相搞挂,单个任务的崩溃不会导致整卡不可用。
配置上通常在 device plugin 的配置文件里指定虚拟化模式。大致是这样:
{ "virtualization": { "mode": "vdcu-timeslice", "slices": 4 } }然后在 Pod 里申请对应资源即可。这里要注意,时间片型 vDCU 对"延迟敏感型"任务不友好:时间片切换意味着任务的实际执行会被打断,长尾延迟会变大。所以我们在生产里只把时间片型 vDCU 给了测试环境和低优推理,线上核心服务一个都不用。
6.2 显存+算力切分型 vDCU
第二种 vDCU 是切分型(可以类比大家更熟悉的 MIG 思路,但实现细节不同):一张物理卡按比例切分成多个独立逻辑卡,每个逻辑卡拥有固定的显存上限和相对独立的算力资源。这种模式下,"这张卡的显存剩多少"是可以被平台准确统计的,调度器终于能按显存去匹配模型,而不是靠数量去碰运气。
切分型 vDCU 的配置和第一种类似,但多了一个显存/算力配比的参数,比如把 64GB 卡切成 2 个 32GB 或 4 个 16GB 逻辑卡。由于显存硬隔离,业务之间的 OOM 不再互相传染,这是它比前两种方案更接近生产可用的原因。
但切分型 vDCU 也有代价:一是切分粒度固定,一旦按 4×16GB 切了,你就没有 64GB 的整卡可用了,需要在建集群前先规划好混合比例;二是部分算子在小显存分区里可能性能下降,尤其是需要大 KV Cache 的推理场景,显存被切小后同一个 batch 能容纳的请求数变少,吞吐反而下降。
6.3 两种 vDCU 怎么选:一张对照表
| 维度 | 时间片型 vDCU | 切分型 vDCU |
|---|---|---|
| 显存隔离 | 无硬隔离,总量共享 | 固定显存上限,硬隔离 |
| 算力分配 | 时间片轮转,竞争式 | 按切分配额,相对独立 |
| 适配场景 | 开发调试、低优推理、批量小任务 | 生产推理、多租户、SLA 明确 |
| 调度感知 | 只感知数量 | 可感知显存上限 |
| 最大风险 | 长尾延迟、内存竞争 | 切分粒度固定,资源碎片 |
在我们集群里,最终方案是"整卡 + 切分型 vDCU"混部:训练和大模型在线推理用整卡;中小模型的在线推理用切分型 vDCU;开发环境和跑批用共享模式。时间片型 vDCU 反而用得最少,因为它的收益和共享模式重叠,又比共享模式复杂,除非你确实需要崩溃隔离,否则性价比不高。
7. 在 DCU 上部署 DeepSeek 的完整实操
7.1 模型选型与权重准备
DeepSeek 系列开源模型里,R1 系列蒸馏版(如 deepseek-r1-distill-qwen-7b/14b/32b)是 DCU 单机单卡/双卡最现实的选择。V3 这种超大 MoE 模型不是不能跑,但需要大规模多卡甚至多节点,对大多数团队来说没必要第一时间挑战。我们选择 14B 蒸馏版作为服务主力:单卡 64GB 显存可以吃下 FP16 权重加足量 KV Cache 和请求并发;如果只有 32GB 卡,就选 7B 或对模型做量化。
权重下载后建议先做一次完整性校验,然后解压到共享存储(我们用的 NFS,生产建议上并行文件系统或对象存储),方便集群内多个节点复用同一份模型文件,避免每个节点都拷贝一份。这一步虽然简单,但在多节点推理场景里能省很多麻烦。
7.2 推理框架选型:vLLM 的 DCU 适配
DCU 上跑 LLM 推理,最主流的路线是用适配了 ROCm/HIP 的 vLLM。vLLM 对 DCU 的支持主要体现在:PagedAttention 的显存管理、continuous batching、量化算子的 HIP 实现。如果你的镜像里没有适配好的 vLLM,建议直接基于官方 PyTorch-DCU 镜像构建,装上对应分支,并验证版本与 DTK 的匹配关系。
一个非常影响吞吐的参数是--gpu-memory-utilization,它决定 vLLM 把多少百分比显存预留给 KV Cache。显存预留太低,最大并发上不去;太高,又可能和 DCU 驱动自身的显存开销冲突。我们用 14B 模型时的经验值是 0.88~0.92,具体根据模型大小和量化方式微调。
7.3 在 K8s/CubeStudio 中发布 DeepSeek 推理服务
以原生 K8s 方式发布一个 DeepSeek 在线推理服务,核心是 Deployment + Service。如果你的推理框架多卡并行,还要注意 tensor parallel 的调度约束——两张卡最好在同一个节点上,否则跨节点走网络通信,吞吐会掉得很难看。
apiVersion: apps/v1 kind: Deployment metadata: name: deepseek-r1-distill-14b spec: replicas: 1 selector: matchLabels: app: deepseek-r1 template: metadata: labels: app: deepseek-r1 spec: containers: - name: vllm-dcu image: hub.example.com/dcu/vllm:0.6.2-dtk24.04 command: ["python", "-m"] args: - vllm.entrypoints.openai.api_server - --model - /models/deepseek-r1-distill-qwen-14b - --tensor-parallel-size - "1" - --max-model-len - "32768" - --gpu-memory-utilization - "0.9" - --port - "8000" ports: - containerPort: 8000 resources: limits: hygon.com/dcu: 1 cpu: "16" memory: 64Gi requests: hygon.com/dcu: 1 cpu: "8" memory: 32Gi --- apiVersion: v1 kind: Service metadata: name: deepseek-r1-svc spec: type: ClusterIP selector: app: deepseek-r1 ports: - port: 8000 targetPort: 8000在 CubeStudio 里操作更简单:直接填模型路径、镜像、资源规格、副本数,平台会生成等价的 K8s 对象。但要提醒,多副本服务必须以无状态方式设计,因为 vLLM 各副本之间不共享 KV Cache,请求分发到哪个副本完全由上层决定;如果你要靠副本数扛 QPS,需要确认上层负载均衡策略符合预期。
7.4 压测与调参
启动后用 curl 验证接口:
curl http://<service-ip>:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model": "/models/deepseek-r1-distill-qwen-14b", "messages": [{"role": "user", "content": "你好,介绍一下你自己"}]}'然后做并发压测。我们测下来几个关键结论:一是--max-model-len别贪大,32K 和 64K 对显存占用差距非常大,除非业务真的有长上下文需求,否则按 P99 请求长度加 20% 余量设;二是并发请求到达 32 左右时,单卡 14B 的吞吐就基本到瓶颈了,再往上 QPS 涨不动,延迟反而线性上升;三是如果发现 DCU 利用率只有 40% 左右,优先检查是不是 token 太短或模型并行方式不对,而不是急着加卡。
8. 从驱动到推理的踩坑排查链路
这一章把我实际经历的几个坑按排查链路写出来,比单给结论有用得多。
8.1 容器里看不到 DCU 设备
现象是 Pod 正常 Running,但进容器执行 dcu-smi 报"no DCU found"或者 /dev/dcu 文件不存在。
排查顺序:
- 先在宿主机执行 dcu-smi,确认驱动正常、卡在线;
- 在宿主机用一个临时容器手动加 --device 参数,确认容器运行时插件是否工作;
- 如果手动可以、K8s 不行,检查 device plugin 的 DaemonSet 是否在节点上运行,以及 plugin 日志里有没有 Allocate 调用;
- 检查 Pod 的 spec 是否真的带上了 hygon.com/dcu 的 limits(很多平台模板会漏掉)。
我们当时的问题出在容器运行时配置没生效:改完 daemon.json 后只重启了 docker,kubelet 缓存的容器运行时还是旧的,导致注入失败。重启 kubelet 或者重启节点解决。
8.2 Pod 一直 Pending 调度不上去
现象是新提交的 DCU 任务一直 Pending,描述里看到 "0/8 nodes available: 8 Insufficient hygon.com/dcu"。
先别急着加机器,按这个链路查:
kubectl describe node看 allocatable 里 hygon.com/dcu 的值是否大于 0;- 如果节点上明明有卡但 allocatable 为 0,查 device plugin 日志,大概率是 plugin 上报失败或与 kubelet 握手异常;
- 如果 allocatable 正常但就是调度不出去,检查 DaemonSet 是否真的在每个有卡节点上运行,以及是否被 taint 挡住;
- 注意多卡任务(申请 2 张卡)的调度条件:K8s 默认调度器是逐个节点匹配的,如果 2 张卡分布在两个节点上,你是拿不到 1 个 2 卡任务的,这在大模型训练里尤其常见。
如果是 CubeStudio 这类平台,还要看平台自己的资源池是否把 DCU 节点正确纳管了。平台界面显示有卡、但底层没有打对 label,也会导致任务永远在队列里。
8.3 推理过程 OOM
前几分钟正常,并发一高就 OOM,而且整卡上其他任务也跟着挂。
这类 OOM 大多是 KV Cache 预留问题。vLLM 在启动时按 gpu-memory-utilization 预留显存,但如果你切分型 vDCU 的逻辑卡本身显存就小,0.9 的比例就会把显存吃光。我们的解法是把 gpu-memory-utilization 调低到 0.85,并给 Pod 的 limits 留出 10%~15% 的显存水位,宁可少几个并发,也不要触发驱动级 OOM 把整张卡拖崩。还有一种场景是共享或时间片型 vDCU 下多个容器显存叠加超限,这种就只能靠切分型 vDCU 或者物理上分开解决,代码层面没有银弹。
8.4 多卡通信性能远低于预期
DeepSeek 多卡部署后,总吞吐没有随卡数线性增长,甚至掉到单卡的 70%。
排查链路:
- 确认节点上多卡之间的互连拓扑。用 dcu-smi 或 rocm-smi 查看拓扑,如果两张卡走的是 PCIe 而不是高带宽互连,tensor parallel 通信开销会吃掉大部分收益;
- 检查是否设置了集合通信库的环境变量。DCU 的 HiCCL 通常需要配置 HCCL 相关环境变量,比如绑定正确的网卡接口,不设的话默认可能会走错误的路由;
- 检查 Pod 的 CPU 绑核情况。通信密集型任务如果 CPU 被调度到不同 NUMA 节点,延迟会明显上升;有条件就上拓扑感知调度(比如 Kubernetes Topology Manager),把 DCU 设备和 CPU/NUMA 绑定在同一区域。
最后给个通用建议:任何 DCU 问题,先把"宿主机原生环境能不能复现"这个边界画出来。宿主机能复现,问题大概率在驱动或 DTK;宿主机能跑但容器不行,问题在容器运行时或镜像;容器可以但 K8s 不行,问题在 device plugin、调度或平台。这个边界一画,排查范围能缩小 80%。
9. 生产环境的配置参考与优化建议
9.1 我们最终采用的配置清单
给一个可以直接抄的生产配置思路(以 4 节点、每节点 8 张 64GB DCU 为例):
| 层面 | 配置项 | 我们的建议 |
|---|---|---|
| 驱动 | DCU 驱动版本 | 与 DTK 版本严格对应,升级前看 release notes |
| 容器运行时 | Docker/containerd runtime | 配置 DCU runtime,重启 docker+kubelet |
| 资源上报 | device plugin | DaemonSet 部署,按整卡+共享+vDCU 三种配置拆分 |
| 调度 | 显存感知 | 用 CubeStudio 资源池按卡型隔离;原生 K8s 考虑调度器扩展 |
| 存储 | 模型权重 | 放并行文件系统,多节点复用 |
| 推理 | vLLM-DCU | gpu-memory-utilization 0.88~0.92,max-model-len 按业务定 |
| 监控 | 指标采集 | dcu-smi 定时采集显存/温度/利用率,接 Prometheus |
每个节点既要保证有足够的 CPU 和内存给 DCU 任务(一般建议至少 16 核 64GB 起步,否则容易出现 CPU 等待导致 DCU 空转),也要提前规划好网卡和存储带宽。很多团队只盯着 DCU 卡数,最后卡利用率上不去,一半原因是 CPU、网络、存储成了瓶颈。
9.2 运维与监控的细节
DCU 的监控和 NVIDIA 不太一样:dcu-smi 输出项虽多,但最需要盯的是显存占用率、温度、利用率以及卡是否进入 ECC 报错状态。建议在节点上用一个 DaemonSet 定期采集 dcu-smi 的 JSON 输出,打到 Prometheus,再在 Grafana 里按节点、按卡维度展示。这样当共享模式或时间片型 vDCU 下出现显存竞争时,你能第一时间在监控上看到哪张卡在打抖,而不是等业务方报障。
日志和告警方面,device plugin 和 vLLM 的日志都必须集中收集。我们吃过一次亏:vLLM 因为一个请求触发了内部异常,CPU 被打满但没有崩溃,业务侧表现为请求超时,由于日志散在节点上,排查花了整整一个下午。后来把所有 Pod 日志接到统一的日志平台,再按 model、service、node 三个维度打标签,五分钟就能定位。
9.3 后续可以扩展的方向
DCU 集群跑稳之后,可以往三个方向继续做深:一是训练侧,把 PyTorch-DCU 和 HiCCL 接入到分布式训练框架,做更大规模模型预训练和微调的弹性调度;二是推理侧,接入更完整的服务网格和灰度发布能力,让 DeepSeek 这类大模型服务可以平滑升级、按流量切分;三是资源侧,在 CubeStudio 上做更细粒度的配额和计费,让不同业务团队按真实用量分摊成本。
最后分享一个个人的小体会:接 DCU 这件事,最忌讳的是拿 NVIDIA 的整套方法论生搬硬套。DCU 有它自己的软件栈和生态节奏,整卡、共享、vDCU 以及推理框架之间是全链路联动的,不是某一个组件换一下就完事。我们也是从整卡入门,被共享模式的显存坑过一次,最后才依赖切分型 vDCU 把生产稳下来。如果你刚起步,建议按"先把整卡链路打穿 → 再引入共享/虚拟化 → 最后上推理框架"的顺序走,每一步都留足验证时间,这样踩坑成本最低。