HAMi在GPU云平台中的共享调度与异构纳管实践
发布时间:2026/10/6 3:34:52 作者:尧图编辑部 阅读量:1,286

这两年我一直在折腾GPU云平台。最大的感受是GPU这玩意儿跟CPU内存不一样它不是天生适合“上云”的。你把它按整卡租贵得吓人客户嫌浪费你把它切小了分着用隔离做不好一个任务就能把整卡显存打爆。GPU利用率、弹性调度、异构适配——每一件事都能让做平台的人头大好几圈。DaoCloud用HAMi来搭GPU云平台这件事我觉得挺有代表性——它解决的恰恰是“复用效率、隔离安全、异构纳管”这三个核心问题。HAMi这个项目简单说是一个面向Kubernetes的异构设备管理中间件社区里常叫它“GPU共享调度器”。它能做到一张物理GPU按需切分成多个虚拟GPU给不同任务分显存、分算力还能让NVIDIA之外的国产芯片也走同一套调度逻辑。我把这套东西在我们自己的集群里实际跑了一遍也拆过DaoCloud公开分享的架构资料下面把设计思路、部署细节和踩坑点一次性说清楚。1. 为什么GPU云平台需要更灵活的底座1.1 传统GPU使用的三大痛点闲置、排队、难共享很多团队做GPU云平台第一版都是“裸卡直挂”——一张A100只能被一个Pod独占租户要多大给多大不切分、不隔离。这方案表面省事实际上一言难尽。首先是浪费。跑NLP推理的Pod可能只要4GB显存你却得给它一整张40GB的卡剩下36GB闲着等下一单。AI训练任务又是另一回事多卡并行时显存占用不均衡某些卡可能只用了70%其余就空转。我见过不少内部集群整卡利用率长期徘徊在20%上下算力没少买活没多干。其次是排队。独占模式下只要卡被占着后面的任务只能干等。尤其推理类在线服务用户请求是持续不断的你没法等“独占窗口”只能不停扩机器成本翻倍。第三是难共享。有人会试着用Kubernetes的Device Plugin原生能力去“切”GPU但原生方案一般不提供显存隔离和算力隔离。说白了就是多个Pod能同时用一张卡可谁也别想管住谁。某个任务一不小心触发OOM或者吃满显存整张卡崩溃邻居全部陪葬。这三个痛点正是HAMi这类“GPU池化”中间件存在的理由。它的核心思路是把物理GPU抽象成可细粒度分配的资源池让“共享”变成一种可控、可度量的默认形态。1.2 HAMi是什么为什么DaoCloud会选它HAMi的完整名称是Heterogeneous AI Computing Middleware从开源社区的定位看它就是专门解决Kubernetes环境下异构设备调度问题的。它做的事情主要有三件一是把GPU的显存、算力进行虚拟切分二是提供自定义调度器让这种切分能被精确调度三是屏蔽底层芯片差异让英伟达、昇腾、寒武纪等不同厂商的卡都能用同一套API托管。DaoCloud选它做GPU云平台底层我判断主要是看中两点。第一是“异构”这件事。国内产线上的GPU早就不是NVIDIA一家独大了。昇腾被政企客户点名要寒武纪在某些场景性价比确实香但它们的驱动、runtime、监控接口全都不一样。如果用Hami统一纳管上层平台不用为每种芯片各写一套适配逻辑省掉的开发量是相当可观的。第二是调度灵活性。HAMi不是简单把GPU“从1切成N”它支持“整卡独占、单卡多租、多卡共享”多种模式并存还能按显存和算力百分比双重维度去分配资源。比如一个Pod要30%的算力和8GB显存它可以在调度阶段就精准找到合适的卡并预留资源而不是等Pod跑起来才发现卡不够用。站在云平台建设角度HAMi替代的是原来“人肉分配GPU”的原始阶段。你不能说它有多了不起但用完之后再回到裸卡模式我是真不习惯了。2. HAMi核心机制拆解资源池化与调度原理2.1 设备共享一张4090怎么让四个人同时用先解决“怎么切”的问题。HAMi的共享方案是在每个GPU节点上运行一个Device Plugin它的工作流程可以理解为“三层翻译”。第一层把物理GPU信息上报给Kubernetes。Device Plugin会感知节点上有几张卡、每张卡多大显存、支持什么算力特性然后在节点上生成扩展资源比如nvidia.com/gpu。这一步和NVIDIA官方Device Plugin没什么本质区别。第二层把“切分规则”变成一个全局配置。HAMi的调度器会维护一个集群级别的资源视图上面记录着每张卡已经被切成了多少块、每块分到了多少显存和算力。这个视图存在ConfigMap里动态更新。第三层给每个Pod“虚拟GPU”。当一个Pod申请nvidia.com/gpu: 1但声明要nvidia.com/gpumem: 8Gi时HAMi会在目标节点上创建一个虚拟GPU设备。这个虚拟设备在容器里看起来就像一个普通的GPU但实际上它的显存访问范围、算力上限都被底层的控制逻辑约束住了。一句话总结共享不是靠物理改装纯粹是软件层面的“画地为牢”。你用的时候觉得自己独占了一片空间其实是平台帮你把一张卡围成了几个格子。2.2 自定义调度器与无损显存隔离这块和原生Kubernetes调度有较大差异值得多说几句。Kubernetes原生调度器在处理GPU时非常“笨”——它只知道节点上有几张卡不知道每张卡剩多少显存。所以如果你申请1块GPU它只会找一张有卡且卡数够的节点至于这张卡够不够你的模型跑它是不管的。HAMi的做法是“替换式调度”。它提供了一个自己的调度器替代默认的kube-scheduler参与调度流程。这个调度器启动时会读取全局设备共享列表调度时不仅看节点上有没有GPU还要看目标卡的具体切分情况。Pod的显存请求、算力请求会被换算成“这张卡可不可以容纳这次申请”然后精确匹配。让我用一个实际表格来说明几种调度形态调度形态资源声明方式物理效果适用场景整卡独占nvidia.com/gpu: 1不声明mem/core独享整卡全部显存和算力大模型训练、需要稳定性的任务按显存共享nvidia.com/gpumem: 8Gi多个Pod共用一张卡显存硬隔离推理服务、数据预处理显存算力共享nvidia.com/gpumem: 8Ginvidia.com/gpucores: 30显存和算力双重隔离混部场景跑批和在线共存多卡聚合nvidia.com/gpu: 2两张卡同时分配给一个Pod分布式训练再说“无损显存隔离”。业界有一种被广泛应用的技术叫MPSMulti-Process Service它通过GPU的硬件上下文机制实现算力分区但它的棘手之处在于显存并不完全隔离一个进程超额使用仍可能影响别人。HAMi的显存隔离做得更彻底一些它通过拦截GPU底层调用在驱动层把每个容器可用的显存范围框住超限即报错。实际测试中这种隔离方式对训练性能的损耗常被控制在很低的水平不像传统虚拟化那样有明显损耗。2.3 异构芯片支持不只NVIDIA前面提到“异构”是HAMi的一大卖点。具体到技术上它通过定义一套统一的Device接口把不同芯片的插件都纳进同一个调度框架。以昇腾为例它的NPU有自己的驱动、自己的显存语义甚至资源名都不同通常叫huawei.com/Ascend910。如果平台只按NVIDIA的方式写死了那昇腾卡进来全得重写。HAMi的做法是让每种芯片对应一个Device Plugin实现但所有插件上报给调度器的信息都遵守统一格式。这样上层看到的永远是一个“设备池”而不是一堆五花八门的硬件。这个设计对云平台建设者来说意义很大——你不用等客户定了芯片型号再改底座硬件自然是“插上即用”。我在实际操作中甚至把NVIDIA和昇腾混在一个集群里照样能调度客户完全无感。3. 平台架构设计从裸卡到可运营的GPU云3.1 控制面与数据面的分工HAMi在平台里分两个层面干活一个管调度一个管运行理解清楚这两块就懂了整个系统。控制面上HAMi Scheduler负责监听所有Pod的创建事件。它先看Pod请求了什么资源再对照全局设备列表决定调度位置。调度完成后一些“精细化动作”需要通过Webhook实现——比如给Pod自动注入虚拟GPU的环境变量和设备映射。很多人第一次接触会忽略Webhook其实没有它Pod就算被调度到卡上容器里也找不到虚拟设备。数据面上每个节点跑着一个DevicePlugin和一套共享控制组件。DevicePlugin负责向kubelet上报设备同时接收来自调度器的指令确定该给哪个容器分配哪个虚拟GPU。容器跑起来后每次GPU调用都会经过这层控制从而实现显存限额和算力限制。用一句话区分控制面管“去哪”数据面管“怎么跑”。任何一边出问题共享就玩不转。3.2 配额、计费、监控如何联动一个GPU云平台如果只解决调度那离“可运营”还差得远。DaoCloud把HAMi接入云平台后我关注到他们做了三层联动。第一层是资源配额。在Kubernetes的Namespace层级设置LimitRange用户可以限制某个团队最多能申请多少显存。HGAMi的显存请求会被转换为标准Kubernetes资源计数这样就天然支持了多租户隔离。比如A团队限额40GB显存那么它把显存切得再碎总和也不能超过40GB。第二层是计费。共享模式下计费不能再按“卡时”来算了。按显存算费更合理8GB跑一小时和40GB跑一小时成本天差地别。HAMi上报的显存、算力占用数据就是计费系统的原始素材。我见过一些平台按“GB·小时”计费这完全建立在细粒度资源分配能力之上。第三层是监控。GPU云平台必须能实时看到每张卡的分配率、利用率、显存占用。这里要注意共享模式下传统DCGM监控看到的是整卡数据不够精确需要结合HAMi的分配信息做二次加工才能画出一张“哪块卡被哪个任务占了多少”的视图。3.3 调度策略设计共享、独占、排队HAMi给了很强的底层能力但调度策略要靠平台自己设计。就拿调度优先级的取舍来说我总结出三条经验。经验一在线推理任务优先用显存共享但算力必须隔离。推理服务大多是延迟敏感型如果旁边跑着一个吃算力的训练任务响应时间会飘。所以对推理Pod一定要同时声明gpucores把算力上限锁死。经验二训练任务尽量整卡或超大块。大模型训练通常需要多卡通信切片太碎会导致通信效率下降。建议训练Pod以“整卡”为单位调度最多允许它在少数共享卡上跑。经验三设置合理的“碎片整理”机制。GPU切分久了会产生显存碎片某张卡剩10GB另一张剩15GB就是拼不出一块40GB。平台需要定期将小Pod迁移或重新调度把碎片拼成大块。这一点HAMi本身不会自动做平台层面要有检查与重调度的定时任务。4. 实操部署HAMi并验证GPU共享4.1 环境准备与组件安装我们以Kubernetes 1.28版本、NVIDIA驱动535系列为例跑一遍完整部署流程。前提条件集群节点已经装好GPU驱动和容器运行时containerd版本≥1.7并且Kubernetes开启了DevicePlugins特性。HAMi提供了Helm Chart安装很直接# 添加HAMi仓库并更新到最新Chart版本 helm repo add hami https://project-hami.github.io/HAMi helm repo update helm search repo hami -l # 安装namespace建议用kube-system helm install hami hami/hami --namespace kube-system --create-namespace安装完成后需要等几分钟让各个组件就位然后确认关键Pod状态kubectl get pods -n kube-system -l app.kubernetes.io/namehami正常情况下你会看到三种Podhami-scheduler调度器、hami-device-plugin每节点一个、hami-webhook注入用。如果hami-device-plugin状态正常但没有Ready大概率是节点GPU驱动或运行时权限有问题需要检查kubelet日志。4.2 配置DevicePlugin与调度器部署只是第一步关键配置集中在HAMi的ConfigMap里。编辑它kubectl edit configmap hami-config -n kube-system核心配置段大致长这样data: config.yaml: | nvidia: resourceName: nvidia.com/gpu memoryUnit: GiB nodeSelector: gpuType: nvidia scheduler: default: true deviceMemoryScalar: 1解释几个容易踩坑的配置memoryUnit推荐设成GiB否则容器内看到的显存数量和Unit换算容易对不上尤其是用了不同显存规格卡的时候。nodeSelector是给异构集群用的。如果节点上有NVIDIA和昇腾这里通过节点标签来区分哪种卡由哪个插件接管。deviceMemoryScalar表示显存申请的倍率一般保持默认1。配置完成后重启DevicePlugin让配置生效kubectl rollout restart daemonset/hami-device-plugin -n kube-system还要确认调度器已经接管Kubernetes的默认调度。检查方法找一个Pod调度事件看是不是由hami-scheduler处理的。如果你发现调度器没有接管需要修改kube-scheduler的配置将默认调度器替换为HAMi的调度器或者用--scheduler-name方式指定。具体操作方式取决于你的集群初始化方式kubeadm还是托管型务必先确认再动手。4.3 提交共享任务并验证调度结果调度配置完成后我们来提交一个带显存和算力限制的Pod。示例YAML如下apiVersion: v1 kind: Pod metadata: name: gpu-share-test spec: containers: - name: main image: nvidia/cuda:12.2-base command: [nvidia-smi, -L] resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 8Gi nvidia.com/gpucores: 30注意这里的资源声明方式nvidia.com/gpu: 1表示要1个虚拟GPUgpumem限定显存8GBgpucores: 30表示该Pod最多使用这张卡30%的算力。提交后观察Pod落在哪个节点、哪个设备kubectl apply -f gpu-share-test.yaml kubectl get pod gpu-share-test -o wide kubectl describe pod gpu-share-test | tail -20如果调度正常describe输出里会显示类似“Successfully assigned default/gpu-share-test to worker-node-gpu-02”的调度结果并且Events里不会出现GPU资源不足的警告。进入Pod验证隔离是否生效kubectl exec -it gpu-share-test -- nvidia-smi你会看到容器里只显示这8GB显存可用哪怕物理卡显存是40GB。这才是隔离生效的标志。如果能看到整卡显存说明虚拟化层没起作用要检查DevicePlugin是否上报了虚拟设备。再验证算力隔离。跑一条耗时操作比较GPU算力kubectl exec -it gpu-share-test -- bash -c time matrix_mul_test多跑几次看耗时上限是否稳定在30%算力对应的水平附近。如果耗时有明显跳动可能算力隔离没完全生效需要确认MPS或底层算力控制组件运作状态。5. 常见问题与排查心得5.1 任务调度不生效排查我遇到最多的一个问题部署完之后GPU请求还是被默认调度器接走了Pod倒是可以调度但根本没有进行共享切分。排查步骤基本是固定的检查Pod的schedulerName是不是指向HAMi的调度器。如果是默认名大概率是调度器替换没成功。检查hami-scheduler日志。如果出现“failed to get device list”之类报错说明调度器无法访问DevicePlugin上报的数据需要确认DevicePlugin是否注册到kubelet。检查节点上是否有虚拟GPU设备。执行ls /dev/vgpu*或查看DevicePlugin日志如果设备文件不存在说明DevicePlugin上报失败。这类问题80%出在“调度器没接管”和“DevicePlugin没上报”两个环节。别急着查复杂配置先按顺序过一遍这三点。5.2 显存隔离失效或OOM处理显存隔离失效通常表现为容器里能查到超过申请额度的显存或者某个Pod把显存耗尽后整卡崩溃。排查看三处确认申请字段是否写对。很多新手只写nvidia.com/gpu: 1忘了写nvidia.com/gpumem那HAMi默认当成整卡申请来调度自然没隔离。确认设备插件版本和内核驱动匹配。HAMi显存隔离依赖特定版本的CUDA或者驱动接口驱动版本过旧会导致拦截逻辑失效。确认容器运行时以GPU模式启动。如果容器没请求GPU资源那它走的不是虚拟GPU通道隔离自然不存在。处理OOM还有一点心得共享卡上如果某个Pod触发OOM建议平台侧自动对该Pod做驱逐和重启并在事件中记录“OOM Killer triggered by neighbor”之类的备注方便租户定位问题而不是简单怪到平台头上。5.3 性能衰减与碎片化调优共享GPU跑久了性能会衰减这是绕不开的但有办法控制。算力衰减的主要来源是上下文切换。如果一张卡上跑了太多小PodGPU需要在多个上下文之间频繁切换训练类任务延迟会明显上升。我的建议是拉起类任务多的场景限制单卡上的Pod数量。比如一张A100最多跑4个共享Pod超过就排队等待保吞吐而不是保并发。显存碎片则要靠“重调度”。平台可以定期扫描每张卡的剩余显存和分配形态如果剩余“碎片”多且碎就主动驱逐部分可重启的Pod重新分配大块显存给高优任务。HAMi允许Pod被驱逐后在新节点重建配合Kubernetes原生的PodDisruptionBudget可以做到无损重排。另外如果条件允许给共享池单独配置“保底资源”。比如每张卡保留10%算力和2GB显存不参与切分用于承担突发开销。这个保底池会让总利用率低几个百分点但能让共享模式的稳定性上一个台阶。6. 一些不在文档里的体会最后说点HAMi使用中的“私房经验”。第一共享模式一定要配监控大盘。HAMi给你的调度信息如果不用起来就等于白给。把“每张卡的分配率、每块虚拟GPU的实时使用率、各租户累计消耗”做成三个核心面板平台管理员的日常巡检就轻松多了。我见过不少团队前期不重视出了问题才去翻日志效率低得吓人。第二升级时要格外小心。HAMi版本升级除了镜像版本还涉及CRD和ConfigMap结构变化。升级前务必在测试集群跑一遍全套回归重点看老Pod是否还能正常调度。升级过程中不要同时升级DevicePlugin和Scheduler先升Scheduler再滚升DevicePlugin减少窗口期风险。第三异构集群的“同构很重要”。虽然HAMi支持异构纳管但尽量把同型号的卡分到同一故障域。如果昇腾和NVIDIA混在同一个节点池甚至同一台机器上这种配置虽然技术上可行一方的驱动更新往往会影响另一方排查起来极为痛苦。按型号分节点池、分亲和性是最省心的做法。第四HAMi不是万能药。如果你的业务是8卡以上的大规模分布式训练裸卡直挂反而更合适。共享模式的价值主要体现在中小任务、推理服务和提升空闲资源利用率上。平台层设计时要同时保留“独占模式”和“共享模式”两条通道让租户自己选。这样既满足了性价比诉求又给高端客户留了稳定性的退路。把HAMi塞进云平台之后最直观的变化是资源利用率从原来不到30%提到了60%以上租户排队时间也从“按天等”变成“按分钟等”。中间踩过的坑不少但每次折腾完查清楚原因都会对这套体系的理解更深一层。如果你也在建设GPU云平台我的建议是先从一张测试卡开始把调度、隔离、监控、计费全链路跑通再慢慢扩大规模。这套东西的收益曲线是越来越陡的值得投入时间。