DCU技术达人
新人贴
把海光 DCU 八张卡当八张工位管:一张卡位表和四条排卡规矩
2026-10-21 10:36:56
28
## 1. 测评对象与要解决的问题 被测对象是一台海光 DCU 服务器:8 张卡,单卡 64GB 显存,合计 512GB;实例通过 `HIP_VISIBLE_DEVICES` 显式钉卡,推理侧为 vLLM 多实例加 8000 端口反向代理,业务端口 8002–8009 按卡号映射,台账随 git 管理。评测周期内这台机器同时承载过四类负载——一套多实例多模态推理服务、一个 0.6B 文本分类常驻服务、一个 32B 大模型推理,以及不定期插入的全量微调训练。 512GB 的总显存听起来宽裕,实测结论相反:四类负载同机共存时,瓶颈不在容量,而在分配。评测前期记录到的三类故障都指向同一个缺口——没有一张"哪个任务在哪个卡上"的登记: | 故障现象 | 直接诱因 | | --- | --- | | 服务重启后端口被占 | 端口无登记,临时调试进程占了常驻服务的口 | | 新实例启动报显存不足 | 进程落到非预期卡上,撞上已占卡 | | 训练任务上卡后推理抖动 | 训练与推理被排进同一张卡 | 三类故障的共同点是:出事时没有人能回答"这张卡上现在是谁"。本篇报告的解法是把 8 张卡当作 8 个工位,建立一张卡位台账,并配套四条排卡规则。以下按拓扑检查、台账结构、排卡规则、端口规划、变更纪律的顺序展开。 ## 2. 前置检查:八张卡在拓扑上不等价 排卡之前先做了一项常被跳过的检查:卡间 NUMA 亲和性。用 `rocm-smi --showtoponuma` 可以看到,规格完全相同的 8 张卡在拓扑上两两分组,每两张卡共享一个 NUMA 节点,跨组通信需要绕经 Socket。 这台机器的分组是 HCU0+HCU1、HCU2+HCU3、HCU4+HCU5、HCU6+HCU7。对排卡的含义用一张表说明: | 任务类型 | 显存特征 | 拓扑要求 | 排卡策略 | | --- | --- | --- | --- | | 多实例小模型推理 | 单实例个位数 GB | 无 | 一卡一实例,任意空位 | | 大模型推理(TP=2/4) | 每卡 50GB 上下 | 必须占同组相邻卡 | 按 NUMA 组整块占用 | | 全量微调训练 | 独占 1~2 卡 | 越少干扰他人越好 | 固定占 HCU0 | 实测对比过 TP=2 任务跨 NUMA 组占卡与同组占卡两种排法,前者吞吐下降明显。原因不复杂:跨组意味着每次前向同步的数据搬运路径变长。这一条检查结论决定了后文所有规则的形状。 ## 3. 台账结构 卡位台账一行一张卡,列固定为六项: | 卡号 | 占用者 | 显存水位 | 端口 | 环境/镜像 | 启停脚本 | | --- | --- | --- | --- | --- | --- | | HCU0 | 全量微调训练 | 独占 ~60GB | 无 | 训练环境 | train_start.sh | | HCU1 | 多模态实例 1 | ~50GB | 8002 | vllm-serve | mm_serve.sh 1 | | HCU2 | 多模态实例 2 | ~50GB | 8003 | vllm-serve | mm_serve.sh 2 | | …… | …… | …… | …… | …… | …… | | HCU7 | 多模态实例 7 | ~50GB | 8009 | vllm-serve | mm_serve.sh 7 | 台账随 git 管理,任何变更——上卡、下卡、换端口——都对应一次提交。这个要求看起来形式化,但它回答了一个没有台账时无法回答的问题:某张卡上多出来的进程是谁、什么时候放上去的、为什么放。没有提交记录时,唯一手段是翻 shell history,成功率取决于运气。 ## 4. 四条排卡规则 ### 4.1 训练任务占固定位 全量微调是这台机器上占用最重的负载:独占整卡、单次运行可持续数天、运行期间不可迁移。规则是给它固定 HCU0,所有推理服务一律从 HCU1 起排。 选 0 号卡做训练位有两层考虑:一是多数脚本缺省落在 0 号设备上,把最容易被误占的卡划给唯一允许独占的任务,误占的损害最小;二是规则足够简单,任何人在任何时间接手这台机器,只需要记住"训练在 0,服务从 1 开始",不需要查询。 ### 4.2 小模型多实例:一卡一实例,TP=1 多模态推理所用模型单卡可完整装下,采用 TP=1、一卡一实例,HCU1–HCU7 共 7 个实例,前端反向代理把 8000 端口流量轮询到 8002–8009。 两种方案的实测对比: | 方案 | 实例数 | 单实例 TP | 故障影响面 | 吞吐 | | --- | --- | --- | --- | --- | | 采用:7 实例 | 7 | 1 | 1 个实例 | 高,无跨卡通信 | | 对照:4 实例 | 4 | 2 | 2 张卡 | 低,通信开销无收益 | 结论是:模型装得下时,吞吐靠实例数堆,不靠 TP 堆。TP=2 在这个规模上不带来容量收益,只付出每次前向的跨卡同步成本。附带的收益是故障域隔离:任一实例异常,服务能力损失 1/7,且定位范围锁定在单卡。 ### 4.3 大模型先画框,小服务再补缝 32B 模型 BF16 推理、TP=2 时,实测每卡占用约 57GB(权重加 KV cache)。这类任务必须整块连续占卡,且按 4.1 节的拓扑结论占同组相邻卡——例如 HCU2+HCU3,不能是 HCU2+HCU5。 排卡顺序因此固定为:新的大模型任务先在台账上标出它要占的连续卡位,剩余空位才分配给小服务。评测中验证过反向顺序的代价:先铺满 7 个多模态实例,32B 上线时凑不出一个干净的 NUMA 组,只能下线一个实例重新排布。顺序反过来,这个返工就不存在。 ### 4.4 显式钉卡,禁止运行时自动选卡 这是四条规则中唯一一条属于"必须写进脚本"的。vLLM 类框架在未指定设备时默认从 0 号卡开始找,而 0 号卡在本机是训练位。未登记、未钉卡的新实例会在启动瞬间去抢训练正在使用的卡。 实测记录到的现象:新起实例,日志报 `Free memory on device (...) is not sufficient`,而 `rocm-smi` 显示目标卡是空的。定位结论:进程没有落在操作者以为的那张卡上,缺省选了 0 号设备。处置方式是每个实例的启动脚本显式写死卡号: ```bash export HIP_VISIBLE_DEVICES=4 # 本实例固定在 HCU4 python -m vllm.entrypoints.openai.api_server --port 8005 ... ``` `HIP_VISIBLE_DEVICES` 与 `CUDA_VISIBLE_DEVICES` 在海光 DCU 上通常都可用,建议全机统一用前者,语义更明确,也规避个别框架版本对后者的兼容差异。钉卡信息同时写进启动脚本和台账,不依赖任何人的记忆。 ## 5. 端口分段 显存之外的第二类冲突资源是端口。实测中发生过一次:0.6B 分类服务(float32 权重约 3.2GB,负载很轻)固定在一张卡、端口 8107,机器重启后未第一时间拉起,端口被一个临时调试进程占用,排查耗时远超预期。据此定下分段规范: | 端口段 | 用途 | 分配规则 | | --- | --- | --- | | 8000 | 反向代理入口,对外唯一入口 | 固定,不直接跑业务 | | 8002–8009 | 多模态实例业务端口 | 与卡号一一映射:8002↔HCU1,……,8009↔HCU7 | | 8107 | 0.6B 分类服务 | 固定,管理端口段 | | 9000+ | 临时调试、实验 | 用完释放,不占台账正式位 | 两条设计要点:业务端口与卡号做映射,从端口可反推卡位,排障时省去翻配置这一步;管理端口与业务端口分离,常驻但低频的服务不与业务端口混用同一池子。另有一个细节写进了重启流程:重启前先 `fuser <端口>/tcp` 确认无残留监听,再起新进程。 ## 6. 变更纪律 台账能否长期有效取决于三条例行动作,均已在评测期内固化为流程: 1. **上卡前盘点**。新任务上卡前跑一遍 `rocm-smi`,将 8 张卡实况与台账逐卡核对;不一致时以实况为准,先修表再上卡。实测这一步约 30 秒,绝大多数抢卡事故在这一步被拦下。 2. **停卡后校验**。停止服务不等于资源释放完成。用 `fuser -v /dev/kfd`(或按端口)确认无残留进程握着设备。评测期内记录到一次:某 stop 脚本只终止了父进程,子进程仍持有 `/dev/kfd`,显存数字看起来已释放而卡实际被占,下一个任务上卡即撞。处置是发现残留即手工清理。 3. **每周对账**。台账进 git、变更即提交,提供"何时、何人、为何"的追溯;另每周固定做一次逐卡对账,漂移当场修正。漂移本身不可避免,未被发现的漂移才是故障来源。 ## 7. 一份实拍台账与结论 32B 推理上线后的某一时刻,台账实况如下: | 卡号 | 占用者 | 显存水位 | 端口 | 环境 | 说明 | | --- | --- | --- | --- | --- | --- | | HCU0 | 全量微调训练 | ~60GB / 64GB(93%) | — | 训练环境 | 训练固定位,禁放服务 | | HCU1 | 多模态实例 1 | ~50GB / 64GB(78%) | 8002 | vllm-serve | TP=1,反代后端 | | HCU2 | 32B 大模型 · 前半 | ~57GB / 64GB(89%) | 8003 | vllm-serve | TP=2,NUMA 组 2+3 | | HCU3 | 32B 大模型 · 后半 | ~57GB / 64GB(89%) | 8003 | vllm-serve | TP=2,与 HCU2 成对 | | HCU4 | 多模态实例 2 | ~50GB / 64GB(78%) | 8005 | vllm-serve | TP=1 | | HCU5 | 0.6B 分类服务 | ~3.2GB / 64GB(5%) | 8107 | float32 | 管理端口段 | | HCU6 | 多模态实例 3 | ~50GB / 64GB(78%) | 8007 | vllm-serve | TP=1 | | HCU7 | 多模态实例 4 | ~50GB / 64GB(78%) | 8008 | vllm-serve | TP=1 | 对外流量统一从反向代理 8000 进入,轮询到各多模态实例的 8xxx 业务端口。 这张快照里可见一个由规则推导出的结果:32B 上线占走两张卡后,多模态实例从 7 个收缩到 4 个——4.3 节"先画框"的代价。换来的是全部负载各在其位,评测后半段未再出现抢卡类故障。 结论压缩为四条:按 NUMA 组排 TP 任务;台账进 git、每周对账;所有实例显式钉卡;端口分段并与卡号映射。这套做法没有用到任何超出 `rocm-smi` 和 `fuser` 的工具,全部是登记与核对层面的工作。对一台多负载共存的海光 DCU 服务器而言,分配层面的秩序比容量本身更早成为瓶颈,也更容易用纪律解决。
DCU技术达人
全部评论(0)
只看楼主
暂无数据
--
楼主
Level.2
0 帖子
楼主热帖
暂无数据