
过去两年很多做平台工程和 MLOps 的团队都有同一种体感大模型任务排队等卡要等很久真正申请到 GPU 之后又发现不少时间在“空转”。另一边的同事还在群里问哪个集群有空闲卡可以临时跑一个微调任务。这种“一卡难求”与“算力闲置并存”的现象在 AI 应用进入常态化落地后越来越明显。表面看是资源不够实际上更像资源没有被“组织”起来。这篇文章想把这件偏行业叙事的事拉回到可以落地的技术视角我们怎样通过 GPU 资源池化、队列调度、配额管理、弹性伸缩、可观测性等手段把分散、波动、难以共享的算力重新编排成一个真正可服务多团队的平台。内容会覆盖核心概念、Kubernetes 相关配置示例、推理侧批处理思路以及常见的排错与治理建议。如果你是正在搭建内部 AI 平台的开发者、训练任务比较多的算法团队负责人或者只是想搞清楚“算力池化”到底是什么的后端工程师这篇文章可以直接作为选型和入门参考。1. 一卡难求与算力闲置为什么会同时出现先说结论算力是否紧缺不能只看“卡的总数量”还要看资源能不能被灵活切分、排队和错峰复用。大多数团队的 GPU 使用模型仍然是“任务独占整卡”一台机器只有 8 张卡只能同时服务 8 个任务。哪怕每个任务只需要其中一小部分显存或计算能力剩下的资源也不会被自动释放给其他任务。这种矛盾的典型表现可以归纳成三类第一种是“大卡跑小任务”。大模型训练普遍需要高显存训练卡但同一个集群里也有很多数据预处理、模型评测、小 batch 微调、推理压测等任务。这些任务可能只需要 8GB 或者 16GB 显存却因为调度粒度太粗不得不申请整张 80GB 显存的卡。申请到之后GPU 计算单元大部分时间处于低占用状态显存却成为使用上限。第二种是任务节奏高度抖动。训练任务和推理任务天然具有不同的时间特征离线训练往往要连续占用几小时甚至几天在线推理会随着业务流量出现明显的波峰波谷。如果全部任务都按“长期占用一张卡”来预留空闲时段资源就无法回收而高峰时段又会出现排队。第三种是多团队之间缺少统一排队机制。很多团队习惯按“部门自建小集群”的方式采购集群之间相互不可见任务也无法跨集群调度。于是有些团队负载很高有些团队负载很低。即使大家愿意共享靠群聊和表格人工协调也不可能做到分钟级调度。综合下来“一卡难求”并不只是绝对数量不足很多时候是组织方式出了问题。要解决这个问题就得先把算力从一台台孤立服务器中释放出来变成可被统一调度、切分、计量和回收的逻辑资源。2. “算力”到底需要被如何组织2.1 算力不只是显卡是一条完整技术栈很多文章谈到“算力”第一反应就是购买了多少张 GPU 卡。但在工程实现里真正能对业务产生价值的是 GPU、显存、高速网络、存储、调度系统和模型推理框架共同构成的整体能力。我们可以把算力平台粗略分成几个层次层次主要职责常见技术组件设备层GPU 计算单元、显存、NVLink/NVSwitch 等CUDA、驱动、NCCL资源池化层把物理 GPU 注册成可调度的逻辑资源Kubernetes Device Plugin、MIG调度控制层决定任务何时何地运行、怎样排队Kube-scheduler、Kueue、Volcano、自定义调度器作业执行层承载训练、微调、推理等实际负载PyTorch、DeepSpeed、Triton、vLLM平台入口层向上层用户提供 API、控制台、配额与计量自研控制台、网关、观测体系“重新组织算力”的本质并不是设计一个新的资源抽象概念而是把原来相对静态的 GPU 使用方式改造成一套动态调度系统。其核心动作可以概括为四个词池化、切分、排队、计量。池化是把多台机器上的 GPU 收拢到一个统一资源池里切分是允许一个物理 GPU 被拆成多个逻辑资源或允许多个请求高效共享同一张卡排队是把集群中的稀缺资源按优先级和公平策略分给不同任务计量则是把资源消耗折算成可观测的指标和成本。只有四个动作一起做才算完成了“组织化”。2.2 算力、Token 与 API三个容易混的概念在讨论 AI 平台时有一组词经常被放在一起算力、Token、API。它们不是同一个维度的概念但在一次模型调用链路中会同时出现。算力是资源侧的概念。我们可以用它表示某张卡在一个单位时间内能完成多少次浮点运算也可以用它泛指集群中 GPU 的数量、类型和可用时间。平时说的“算力不够”通常指任务排队时间变长或者单任务执行速度变慢。Token 是模型输入输出的文本切分单位。大模型会把自然语言切分成 token再逐个预测后续 token。业务方通过 API 调用模型时计费通常按 token 数量计算。API 是能力开放的形式。用户不需要关心底层到底用了多少张 GPU只需要把请求发给模型服务端点由平台侧完成资源分配和推理过程。它们的关系可以这样理解平台先准备好算力把模型服务封装成 API用户调用时按 token 计费平台侧记录 token 消耗并折算成算力成本。对算力组织者来说关注的是从 token 消耗倒推资源用量从而判断哪些模型服务值得扩容哪些服务正在浪费资源。3. 从“独占一张卡”到“共享一个池”3.1 单卡资源浪费的典型形态要优化算力先要理解一张 GPU 卡被申请后哪些资源容易被浪费。一是计算单元利用率不高。训练过程中GPU 需要经常等待 CPU 数据预处理、数据加载、分布式通信或者模型算子低效导致的计算间隙。显存看着占了很多但 SMStreaming Multiprocessor利用率可能只有 40% 到 60%。二是显存使用不均衡。有些任务显存占用高但计算量不大有些任务计算密集但显存占用很低。如果系统只按“一张整卡”分配就无法对不同任务做显存和算力的组合调度。三是推理请求的到达不均匀。在线推理服务如果固定申请 N 张卡请求少的时候大量算力闲置请求多的时候又无法应对峰值。要解决上述问题不能单靠某一种技术而需要把“共享”和“切分”组合起来。3.2 GPU 共享与切分的可选方案目前业内比较常见的做法是以下几种它们解决的问题不同适用场景也不一样。机制基本思路优势需要关注的问题整卡独占一个 Pod 独占整张 GPU隔离性强问题容易定位浪费严重无法服务小显存任务MIG 切分将一张 GPU 物理切分成多个独立实例显存和计算隔离都较完善需要硬件和驱动支持不同卡切片规则不同时间片共享让多个进程分时复用同一块 GPU提高计算资源利用率显存隔离较弱需要配置好 GPU 内存限制推理动态批处理多个推理请求合并成 batch 执行大幅提升吞吐适合在线服务会增加单请求排队延迟需要设置超时策略这里特别想提醒一点GPU 共享并不是越激进越好。如果多个任务共享显存时没有做好隔离一个任务显存超卖就可能触发 OOM进而影响同卡上的其他任务。比较稳妥的路线是先整理任务画像再判断哪些任务适合共享。例如离线小批量评测任务往往低优先且可容忍排队适合放入共享队列生产环境的在线推理服务可能对延迟要求很高应该避免与其他大任务放在同一张卡上“抢算力”。从业务价值看让大模型推理服务自己通过动态批处理提高吞吐通常比简单做显存超卖更可控。4. Kubernetes 里如何把 GPU 变成可调度资源4.1 设备插件与扩展资源在 Kubernetes 集群中GPU 并不是默认资源类型。要让调度器感知 GPU需要先安装 NVIDIA 官方维护的 Device Plugin。它会向 kubelet 上报节点上的 GPU 数量并注册一种扩展资源名字通常是nvidia.com/gpu。安装完成后我们可以通过kubectl describe node查看节点是否上报了 GPU 资源kubectl describe node cn-gpu-01 | grep nvidia如果看到类似nvidia.com/gpu: 8的信息说明节点上的 GPU 已经被 Kubernetes 识别。之后 Pod 就可以像申请 CPU 和内存一样申请 GPU。需要特别注意的是GPU 不是可分片的原生资源。在默认情况下一个 Pod 申请到nvidia.com/gpu: 1就意味着独占整张物理 GPU。如果想要做到类似“半张卡”的分配通常需要引入 MIG、厂商自研切分方案或在调度器上层做额外抽象。4.2 一个最小的 GPU 工作负载示例下面是一个使用 GPU 的工作负载 YAML。为了让示例能够直接运行镜像使用了一个包含 CUDA 运行时的 PyTorch 官方镜像容器启动后保持运行方便进入容器查看 GPU 状态。# gpu-workload-example.yaml apiVersion: apps/v1 kind: Deployment metadata: name: gpu-example namespace: default spec: replicas: 1 selector: matchLabels: app: gpu-example template: metadata: labels: app: gpu-example spec: containers: - name: pytorch image: pytorch/pytorch:2.2.0-cuda12.1-cudnn8-runtime command: [sleep, infinity] resources: limits: nvidia.com/gpu: 1执行kubectl apply -f gpu-workload-example.yaml kubectl get pods -l appgpu-example等 Pod 进入 Running 状态后我们可以进入容器执行nvidia-smi查看容器内识别到的 GPUkubectl exec -it deploy/gpu-example -- nvidia-smi正常情况下容器内会看到一张独立的 NVIDIA 显卡。这里要注意YAML 中 GPU 资源通常只写limits不需要写requests。对于扩展资源Kubernetes 默认要求请求和限制相等因此只配置limits是最常见和稳妥的方式。4.3 为什么不要直接在业务 Pod 里塞节点 IP另一个常见误区是为了“确保任务跑到某台机器上”直接在 Pod 里写nodeName或nodeSelector。这样做在资源充足时看似省事实际会把集群调度器绑死。一旦指定了节点即使其他节点有空闲 GPU这个任务也无法过去如果指定节点恰好进入维修或驱动异常状态任务就只能一直 Pending。更合理的做法是用标签描述 GPU 类型再用nodeSelector或nodeAffinity做软性约束。比如给节点打上资源类型标签kubectl label node cn-gpu-01 acceleratornvidia-h100 poolai-training kubectl label node cn-gpu-02 acceleratornvidia-a10 poolai-inference需要某一类 GPU 的负载才声明对应标签。这种方法把“调度到哪台机器”的权利交还给调度器而不是写死在工作负载里。5. 给多团队“排队”队列、配额与优先级5.1 默认调度器解决不了多团队公平性Kubernetes 默认调度器可以为一个 Pod 找到满足资源条件的节点但它并不擅长全局性的排队与公平分配。当一个集群被多个团队共用时很容易出现下面几种现象某个团队连续提交大量训练任务一下子把集群中的 GPU 全部占满其他团队提交的任务只能在 Pending 状态等待甚至一直等到超时。更麻烦的是如果没有准入控制一个低优先级的用户可能反复创建 Pod 尝试“挤进”集群由于任务之间没有优先级区分调度器只能按照创建顺序依次调度导致原本应该优先执行的紧急任务也被堵在队尾。这就像只有一个窗口的食堂窗口本身只负责“有人来就打饭”却不关心哪些人应该排前面、每个人一餐最多打几份饭。因此在多团队场景下我们需要在调度器之上增加队列和配额层。5.2 用 Kueue 做统一排队与配额在 Kubernetes 生态里Kueue 是比较典型的队列方案。它不直接替代 Kube-scheduler而是管理“哪些工作负载可以被创建、什么时候被创建”。Kueue 中比较重要的概念包括 ClusterQueue、LocalQueue 和 Workload。我们需要把集群中的 GPU 总量、团队能使用的上限、优先级等配置放入队列中然后让训练任务声明使用哪个队列。下面这段配置可以看作一个简化示意。由于 Kueue 的 CRD 版本更新较快字段在不同版本中会有差异生产环境落地时应该以你实际安装版本的官方文档为准。apiVersion: kueue.x-k8s.io/v1beta1 kind: ClusterQueue metadata: name: ai-cluster-queue spec: namespaceSelector: {} resourceGroups: - coveredResources: - cpu - memory - nvidia.com/gpu flavors: - name: gpu-flavor resources: - name: cpu nominalQuota: 200 - name: memory nominalQuota: 400Gi - name: nvidia.com/gpu nominalQuota: 32在团队命名空间里创建 LocalQueue并将它指向这个 ClusterQueueapiVersion: kueue.x-k8s.io/v1beta1 kind: LocalQueue metadata: name: algorithm-team-queue namespace: algorithm-team spec: clusterQueue: ai-cluster-queue作业如果要使用队列通常需要在工作负载上增加队列标签或字段。不同类型的训练框架接入方式不完全一样但整体思路一致作业不会直接生成 Pod而是先进入 LocalQueue由 Kueue 判断资源是否充足、是否允许创建。这样做的好处是任务不再以“裸 Pod”的方式无限抢占集群而是先排在队列里。如果团队有突发实验需求还可以为 ClusterQueue 配置较高的nominalQuota或弹性配额当集群有闲置资源时允许临时超用但一旦有高优先级任务进入低优任务会被抢占或回收。这种机制能明显缓解“资源闲着但某团队不可越权使用”的低效问题。5.3 优先级与抢占的工程取舍优先级调度本身容易理解但工程上要谨慎设计。一个简单的优先级模型可以分成三类生产在线任务优先级最高通常由平台保障资源不能被随意抢占。离线训练任务中等优先级可排队可暂停。实验开发任务优先级最低可以使用空闲资源集群资源紧张时优先回收。在 Kubernetes 中优先级可以通过 PriorityClass 表达。例如apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 1000000 globalDefault: false description: 用于生产高优任务但在 GPU 集群里抢占必须考虑显存和计算状态的清理成本。直接杀掉一个正在训练的 PyTorch 任务可能会导致断点丢失如果开启了抢占却没有配套的 checkpoint 恢复机制损失可能远大于收益。因此工程上更推荐的做法是“准入前排队”而不是“运行中随意抢占”。调度器应该尽量在任务启动前就把顺序排好给高优任务预留资源运行中的任务只有到了明确的优先级反转边界才考虑抢占和回收。6. 在线推理侧的“算力组织”批处理与弹性6.1 离线训练和在线推理调度目标不同训练任务的核心目标是“跑得快、能完成”对延迟不敏感但对稳定性要求高。推理任务的核心目标是“单位时间内处理更多请求”同时要控制延迟。两者的资源组织方式也应该不同。训练任务更适合用队列管理任务排队时间稍微长一点通常可以接受推理服务则要作为常驻服务运行需要预留资源、支持自动扩缩容并且尽量把请求量波动消化在服务内部。如果团队把训练和推理混在同一个资源池里需要特别做好在线推理的资源隔离。一个常见事故是白天有人提交了大规模数据并行训练占用了所有 GPU线上推理服务因为无法扩容而延迟上升晚上训练结束推理节点又出现大量空闲。这不是单纯的算力不够而是缺少分时和分池调度。6.2 推理吞吐的关键动态批处理在线推理场景中很多团队只关注“申请了多少张卡”却忽视了模型推理框架本身的批处理能力。传统推理通常会把单个请求单独送给模型执行GPU 在计算一个请求时其他计算单元可能处于等待状态。以 LLM 推理为例模型生成 token 的过程是逐 token 进行的GPU 的算力很难被单个请求完全打满。一次请求的等待时间恰好可以插入其他请求的 token 计算这就是动态批处理的核心思想。目前常见的大模型推理框架普遍支持连续批处理continuous batching。它允许服务器维持一个较大的请求池当 GPU 完成当前批次的一部分计算后可以立即插入新的请求而不是等待整个批次全部结束。这种机制能大幅提高显卡利用率和整体吞吐。因此在评估推理服务需要多少张卡时不要只用“请求总数除以单卡并发”的简单公式。更合理的方式是先压测不同 batch size、不同输入输出长度下的吞吐和延迟再结合线上请求到达速率估算资源需求。往往同样的卡数优化框架配置后能支撑的请求量可以提升数倍。6.3 弹性扩容不是越快越好对在线推理服务很多人会想到 Kubernetes HPA。但 GPU 推理服务有几个特殊问题扩容可能需要重新加载模型权重显存冷启动时间较长缩容过快可能导致正在处理的请求被中断自动扩缩容策略如果只依赖 CPU 指标又不能准确反映 GPU 实际负载。比较稳妥的实践是至少组合两类信号一类是业务信号例如队列中的请求数。如果请求在推理网关或服务内部持续积压说明需要扩容。另一类是资源信号例如 GPU 利用率、显存占用。但 GPU 利用率波动比较大只看瞬时值容易误判。通常可以看过去 5 到 10 分钟的滑动平均值并且给扩容设置一个较高的阈值给缩容设置一个较低的阈值。分时策略同样值得考虑。如果业务流量有明显的早晚高峰可以为推理服务设置最小副本数。白天高峰前提前扩容夜间再逐步缩容。不要盲目追求秒级弹性GPU 节点的增加往往也不是秒级完成的提前规划比临时扩容更可靠。7. 把闲置“看”出来GPU 可观测性与分账7.1 别只盯着 nvidia-smi排查 GPU 问题时多数人第一步是敲nvidia-smi。它能反馈显存占用、温度、功耗和利用率但还不能完整反映“算力是否被有效组织”。如果只通过nvidia-smi发现利用率很低通常已经滞后了。更系统的做法是接入 DCGMData Center GPU Manager指标。NVIDIA 官方提供了dcgm-exporter可以采集 GPU 的核心指标再通过 Prometheus 存储用 Grafana 展示。常见的指标包括指标名称含义关注场景DCGM_FI_DEV_GPU_UTILGPU 计算单元利用率判断计算是否满负荷DCGM_FI_DEV_FB_USED显存已用量判断显存分配是否合理DCGM_FI_DEV_MEM_COPY_UTIL显存拷贝引擎利用率判断是否存在数据搬运瓶颈DCGM_FI_DEV_SM_CLOCKSM 时钟频率辅助判断是否有降频问题DCGM_FI_DEV_GPU_TEMPGPU 温度发现散热与机房环境问题在 Kubernetes 中dcgm-exporter通常以 DaemonSet 方式部署这样每个 GPU 节点上都会有一个 exporter 暴露本机指标。通过 Prometheus 采集后我们能按节点、命名空间、Pod 维度观察 GPU 使用情况。7.2 从“集群利用率”到“任务级效率”集群利用率高并不等于资源用得好。一个训练任务可能让 GPU 利用率长期维持在 90%但模型迭代效率并不高因为计算过程可能包含大量无效等待或低效算子。因此在指标设计上可以把问题拆成两层。第一层是平台层指标集群 GPU 总数、空闲卡数、排队任务数、平均等待时长、GPU 平均利用率、显存平均使用率。这些指标用于回答“资源是否够用、是否在空转”。第二层是任务层指标单任务的 GPU 利用率、吞吐、训练损失下降速度、推理请求的 token 生成速度等。只有把平台层和任务层指标结合起来才能判断某个团队申请 16 张卡到底是合理业务需求还是资源被闲置。在实际平台里要保证每个 Pod 带上团队、项目、任务类型的标签。否则即使采集到指标也无法反查“是哪条业务线在用卡”。7.3 成本归属与预算控制算力成本如果无法归属到具体团队就很难形成反馈机制。内部平台可以建立一套简单的成本模型不一定要做到分毫不差但至少要让业务团队知道自己消耗了多少资源。一种常见口径是按照 GPU 卡时计费团队消耗成本 GPU 卡数 × 卡型单价 × 使用时长不同卡型单价可以根据采购成本、折旧、电力、机房成本折算。如果平台支持共享切分还需要添加一个小于 1 的折扣系数否则用户会倾向于申请独享整卡导致共享配置形同虚设。成本数据需要通过定期账单或控制台报表公开给团队。很多资源浪费并不是业务方有意为之而是他们完全看不到自己的任务占用了多大成本。一旦成本可视化团队自然会主动清理废弃 Pod、缩减长期不用的实验集群。8. 落地路线与常见误区8.1 推荐的三步落地节奏如果团队现在的 GPU 使用仍然处于“人工协调、各自为政”的阶段不建议一步到位建设复杂平台。更顺滑的路径是先盘点现状再做小规模调度试点最后才扩展全平台能力。第一步先做资源盘点。通过nvidia-smi、DCGM 或云厂商控制台统计每个团队申请了多少 GPU、真实跑满的时间占比是多少。如果某个业务方长期申请 16 张卡但实际只用到 4 张这就是最直接的优化点。第二步统一集群入口。把分散的 GPU 服务器纳入同一个集群或同一套管理平面给节点打上类型标签用命名空间区分业务团队先做到“资源可见”。这一步不一定需要复杂调度器只需要让不同团队看到全局资源状态。第三步接入队列与配额。根据团队实际需求为离线训练、在线推理、实验开发分配不同的队列和优先级。引入 Kueue、Volcano 等队列方案逐步把人工协调替换成自动排队。8.2 常见问题速查问题现象常见原因解决思路任务申请 GPU 后一直 Pending集群中没有满足节点标签或 GPU 数量的节点检查节点标签、DCGM 驱动、Device Plugin 上报资源容器内看不到 GPU未部署 Device Plugin 或驱动版本不匹配确认节点驱动可用重启 Device Plugin Pod某团队任务占满整个集群缺少队列配额和优先级策略引入 ClusterQueue/LocalQueue 限制团队资源上限单张卡上跑小任务浪费严重调度粒度太粗只支持整卡独占评估 MIG、时间片共享或动态批处理方案GPU 利用率高但推理延迟也高请求排队过多批处理策略过于激进调整最大 batch、超时时间增加副本扩容不知道哪些业务在大量消耗算力Pod 缺少标签成本无法归属强制命名空间与标签规范建立内部计量账单这里尤其要提醒如果任务长期 Pending不能简单靠“删掉重新提交”解决。正确做法是先通过kubectl describe pod查看调度事件确认是资源不足、节点亲和性不满足还是队列准入没有通过再采取对应措施。在实际 Kubernetes 环境中用户上报 GPU 时也不要轻易使用requests.nvidia.com/gpu: 0.5这种方式。默认的扩展资源不支持小数或切片很多平台上报这种配置并不会真正实现半卡隔离只会让调度行为变得不可预期。如果需要半卡或更细粒度资源应该走平台层或 MIG 方案。9. 最后想说的AI 算力组织这个话题很多人会先想到买更多卡、用更强硬件。但从工程角度看真正直接影响资源效率的往往是上层调度和管理平台。GPU 是一种昂贵、排队感强、碎片化明显的资源把它当成普通容器资源来使用必然会遇到浪费和稀缺并存的问题。值得庆幸的是云原生生态里已经有相当多成熟的组成单元Kubernetes 负责资源抽象Device Plugin 负责 GPU 接入Kueue、Volcano 负责队列与配额DCGM 负责可观测性vLLM 等推理框架负责把单卡吞吐压榨到极致。团队需要做的是把这些组件按照自己的业务特点组装起来而不是每次遇到算力紧张就重复采购。如果当前团队只有几十张卡并且主要通过训练任务提交可以先从 GPU 指标采集和队列排队入手。如果团队同时承担在线推理和离线训练就要认真设计异构资源池和伸缩策略。如果能做到算力从“看上去很多”变成“真正被用明白”一卡难求与闲置并存的矛盾在大多数内部场景里都能得到不小的缓解。希望这篇文章能帮你在搭建算力平台的路上多一条排查思路。后续可以继续关注 GPU 调度策略、推理框架选型和集群成本治理方向也欢迎在实际落地中多压测多记录数据毕竟算力平台没有完美的通用架构只有最适合自己业务节奏的解法。