
1. 从一张GPU账单说起为什么训推一体化绕不开异构算力调度去年底帮一个做多模态内容生成的团队看他们的算力账单发现一个很典型的现象训练集群里8卡A100的利用率长期在35%上下晃推理那边却天天喊卡不够用运维同学只能不停加机器。更离谱的是训练任务排队的时候推理服务占着的卡又在跑一些根本不需要GPU的预处理任务——视频抽帧、文本清洗、格式转换这些活CPU干得好好的非要占着一张卡。这不是个例。只要你的AI平台同时承载训练和推理两类负载异构算力调度这件事迟早会撞到你脸上。所谓异构不只是GPU型号不同而是GPU、CPU、内存、磁盘这四类资源在训推两种场景下的需求曲线完全不一样训练吃显存带宽和卡间通信推理吃并发和首token延迟预处理吃CPU核数和内存吞吐数据加载吃磁盘IO和缓存命中率。把它们塞进同一套资源池靠人肉分配必然是一边饿死一边浪费。AllData数据中台集成Crater这个组合解决的正是这个问题。Crater在这里承担的是算力资源抽象与调度的角色把物理机上的GPU、CPU、内存、磁盘统一纳管成可切分、可配额、可回收的资源池AllData数据中台则负责上层的数据流转、任务编排和AI训推流程的串联。两者合起来目标就是建设一套训推一体化的算力平台——训练任务和推理服务共享同一套资源底座按需分配动态回收。这篇文章适合谁看如果你正在做AI平台的基础设施选型或者手头有一堆GPU服务器但利用率上不去又或者你正在被训练排队、推理缺卡这种两头堵的局面折磨那接下来的内容应该能给你一些可直接参考的思路。我会从资源抽象、GPU切分、训推调度策略、存储与内存协同、以及实际落地时踩过的坑这几个角度把这件事拆开讲清楚。2. Crater在AllData中台里的真实定位它不是又一个K8s2.1 为什么K8s原生调度搞不定训推混合场景很多人第一反应是资源调度用K8s不就行了Device Plugin挂上GPUnvidia-smi能看到卡调度器按卡数分配完事。但真跑起来你会发现几个硬伤。第一K8s的GPU调度是整卡粒度的。一张A100 80G推理服务可能只需要10G显存但K8s会把这整张卡分给这个Pod剩下的70G就锁死了。训练任务想用这张卡排队等着。这就是典型的显存碎片化——卡是分出去了但利用率极低。第二K8s不感知GPU的拓扑结构。8卡机器里卡和卡之间的NVLink带宽、PCIe Switch层级、NUMA节点归属这些信息K8s默认不管。结果就是训练任务被调度到跨NUMA的卡上通信开销直接翻倍训练速度掉30%你都找不到原因。第三训推混合场景下K8s缺乏对任务优先级的细粒度控制。训练任务通常长周期、高吞吐推理服务要求低延迟、高可用。K8s的PriorityClass只能做粗粒度的抢占没法做到训练任务在推理高峰期自动让出部分算力这种动态调整。Crater的价值就在这里。它在K8s之上做了一层算力抽象把GPU、CPU、内存、磁盘这四类资源统一建模支持更细粒度的切分和更灵活的调度策略。你可以把它理解成K8s的算力调度增强层而不是替代品。2.2 Crater的资源模型GPU/CPU/内存/磁盘怎么统一纳管Crater的资源模型核心思路是池化配额回收。物理机上的资源先注册到Crater的资源池里然后按租户、按任务类型做配额划分任务结束后资源自动回收。具体到四类资源GPU支持整卡、vGPU切分、MIGMulti-Instance GPU三种模式。A100/H100支持MIG可以切成1g.5gb、2g.10gb、3g.20gb等规格消费级卡不支持MIG的用vGPU做时间片轮转或显存隔离。Crater会根据任务申请的显存和算力比例自动选择最合适的切分方式。CPU按核数配额支持绑核和NUMA亲和性设置。预处理任务可以绑到特定NUMA节点避免跨节点内存访问。内存按GB配额支持内存超卖但会设置水位线告警。训练任务的数据加载器经常吃大量内存做缓存Crater会监控内存使用超过阈值时触发数据落盘或缓存淘汰。磁盘按容量和IOPS双维度配额。训练数据集读取和推理日志写入对磁盘的压力完全不同Crater会区分顺序读写和随机读写给不同任务类型分配不同的IO权重。这套模型的好处是你在AllData中台上提交一个任务时不需要关心底层是哪台机器、哪张卡只需要声明我要4卡A100、32核CPU、128G内存、500G SSDCrater会自动找到满足条件的资源组合并分配。2.3 和AllData中台的数据流转怎么打通AllData数据中台的核心能力是数据集成、数据开发、数据治理。当它和Crater集成后AI训推任务的数据流就变成了数据从AllData的数据源接入经过清洗转换后写入特征存储或对象存储训练任务通过Crater申请算力后直接挂载这些存储推理服务则从同样的存储读取模型和特征。这里有个关键设计Crater的资源池和AllData的存储层是解耦的。算力调度归Crater数据调度归AllData。训练任务启动时Crater负责把GPU/CPU/内存分配好AllData负责把数据挂载到容器里。两者通过标准接口对接不互相侵入。实测下来这种解耦设计的好处是扩展性强。你换存储后端、换调度器互不影响。坏处是初期集成时需要把两边的元数据对齐比如任务的资源标签和数据标签要能关联上否则排查问题时会对不上号。3. GPU切分与异构调度把一张卡用出三张卡的效果3.1 vGPU与MIG的选型逻辑不是所有卡都适合切GPU切分是异构算力调度里最核心也最容易踩坑的部分。先明确一个原则不是所有GPU都适合切分切分方式选错了比不切还糟糕。目前主流的切分方式有三种切分方式适用卡型隔离级别显存隔离算力隔离典型场景MIGA100/H100/A30硬件级完全隔离完全隔离多租户推理、小模型训练vGPU时间片消费级/数据中心卡软件级部分隔离时间片轮转开发测试、轻量推理vGPU显存隔离部分数据中心卡软件级完全隔离无隔离显存敏感型推理MIG是硬件级切分一张A100可以切成最多7个实例每个实例有独立的显存、计算单元和L2缓存。优点是隔离性极好一个实例崩了不影响其他实例缺点是切分规格固定不够灵活而且不是所有卡都支持。vGPU时间片轮转是软件级切分多个任务共享同一张卡的计算单元按时间片切换。优点是灵活想切多少切多少缺点是隔离性差一个任务把显存吃满其他任务直接OOM。而且时间片切换有上下文开销对延迟敏感的推理服务不友好。vGPU显存隔离是折中方案显存按配额硬隔离但计算单元共享。适合那些显存需求明确、算力需求波动大的推理场景。Crater的做法是根据任务类型自动推荐切分方式。训练任务默认整卡或MIG推理任务根据QPS和延迟要求选择MIG或vGPU显存隔离开发测试任务用vGPU时间片。你可以在任务配置里手动覆盖但默认策略已经覆盖了80%的场景。3.2 显存碎片化治理从分卡到分显存显存碎片化是GPU利用率低的头号杀手。我见过一个极端案例8卡机器上跑了12个推理服务每个服务占一张卡但每张卡的显存利用率只有20%-30%剩下的显存全浪费了。想再部署新服务没卡了。Crater治理显存碎片化的思路是从分卡到分显存。具体做法显存池化把物理卡上的显存统一注册到显存池按MB粒度分配。任务申请的是显存大小不是卡的数量。碎片整理当显存池出现碎片时Crater会触发碎片整理——把低优先级任务的显存迁移到其他卡上腾出连续的大块显存给高优先级任务。超卖与回收允许显存超卖但设置水位线。当显存使用率超过85%时触发告警超过95%时自动驱逐低优先级任务。这里有个实操细节显存超卖的比例怎么定我的经验是推理服务按1.2倍超卖训练任务按1.0倍不超卖。因为推理服务的显存使用有波峰波谷超卖能提升利用率训练任务显存使用是刚性的超卖会导致OOM。3.3 训练任务和推理服务的优先级博弈训推一体化平台最棘手的问题之一训练任务和推理服务抢资源时谁优先直觉上当然是推理优先因为推理直接服务用户延迟高了用户会跑。但训练任务也不能一直饿着否则模型迭代速度上不去。Crater的调度策略是分级抢占动态配额分级推理服务设为P0训练任务设为P1开发测试设为P2。P0可以抢占P1和P2的资源P1可以抢占P2。动态配额给推理服务设置最小保障配额和最大弹性配额。最小保障配额确保推理服务在训练高峰期也能拿到基本算力最大弹性配额允许推理服务在训练低谷期占用更多资源。抢占冷却被抢占的训练任务不会立即被杀掉而是先收到准备让出的信号任务有机会保存checkpoint后再退出。冷却时间默认5分钟可配置。这套策略实测下来推理服务的P99延迟能稳定在SLA以内训练任务的资源等待时间也比纯静态分配缩短了40%左右。3.4 一个真实的调度案例8卡A100怎么同时跑训练和推理说个具体案例。一台8卡A100 80G的机器需要同时跑一个7B模型的微调训练需要4卡预计跑6小时三个推理服务分别需要10G、15G、20G显存两个数据预处理任务纯CPU各需8核Crater的调度方案训练任务分配4张整卡GPU 0-3走NVLink互联NUMA亲和到CPU 0-31。推理服务在剩余4张卡GPU 4-7上做MIG切分GPU 4切2个10G实例GPU 5切1个15G1个10GGPU 6切1个20G1个10GGPU 7保留整卡给突发流量。预处理任务绑核到CPU 32-47NUMA亲和到GPU 4-7所在的节点避免跨NUMA访问。磁盘IO训练任务走SSD顺序读推理服务走NVMe随机读预处理任务走HDD顺序写。最终这台机器的GPU利用率从原来的35%提升到78%推理服务的P99延迟稳定在200ms以内训练任务也没有因为资源竞争而变慢。4. 训推一体化的存储与内存协同别让数据加载拖垮GPU4.1 训练数据管道的IO特征与磁盘配额训练任务的数据加载是个容易被忽视的性能瓶颈。很多人把GPU利用率低归咎于算力不够实际上很多时候是数据加载跟不上GPU在等数据。训练数据管道的IO特征顺序读为主训练数据集通常是大文件顺序读取比如TFRecord、WebDataset格式。高吞吐8卡A100训练时数据加载吞吐需要达到2-4GB/s才能喂饱GPU。随机性数据shuffle会引入随机读但通常有缓存层缓冲。Crater对训练任务的磁盘配额策略是按吞吐保障IOPS限制双维度分配。吞吐保障确保数据加载不会成为瓶颈IOPS限制防止训练任务把磁盘打满影响其他任务。具体配置建议小规模训练1-2卡预留500MB/s吞吐5000 IOPS中规模训练4-8卡预留2GB/s吞吐20000 IOPS大规模训练16卡以上预留5GB/s吞吐50000 IOPS建议走分布式存储4.2 推理服务的KV Cache与内存水位线推理服务和训练任务对内存的需求完全不同。训练任务吃内存主要在数据加载和梯度累积推理服务吃内存主要在KV Cache。KV Cache的大小和序列长度、batch size、模型层数直接相关。以7B模型为例序列长度2048batch size 16FP16精度KV Cache大约需要2-3GB。如果并发请求多KV Cache会线性增长。Crater对推理服务的内存管理策略水位线告警内存使用率超过70%告警超过85%触发KV Cache淘汰。KV Cache淘汰优先淘汰最早请求的KV Cache保留最近请求的。内存配额给每个推理服务设置内存上限超过上限时拒绝新请求而不是OOM。这里有个经验值推理服务的内存配额建议设为模型权重KV Cache峰值20%缓冲。缓冲留少了容易OOM留多了浪费。4.3 数据本地性优化让计算靠近数据数据本地性对训练性能的影响经常被低估。如果训练任务的数据在远端存储每次epoch都要从网络拉取网络带宽会成为瓶颈。Crater的数据本地性优化策略数据预热训练任务启动前Crater会检查数据是否在本地缓存不在的话触发预热把数据从远端拉到本地SSD。亲和性调度调度训练任务时优先选择已经缓存了该数据集的节点。缓存淘汰本地SSD缓存按LRU淘汰但训练任务正在使用的数据集会被标记为锁定不会被淘汰。实测数据一个10GB的训练数据集从远端存储读取需要约2分钟按100MB/s带宽算从本地SSD读取只需要20秒。如果每个epoch都省2分钟跑100个epoch就是200分钟相当于多跑了3个多小时。5. 落地时踩过的坑从资源超卖到调度死锁5.1 资源超卖导致的OOM雪崩刚上线Crater的时候我们为了提升利用率把GPU显存超卖比例设成了1.5倍。结果有一天推理服务流量突增多个服务的KV Cache同时膨胀显存瞬间被打满触发OOM。更糟糕的是OOM导致Pod重启重启后又要重新加载模型加载过程中又占显存形成雪崩。排查过程先看Crater的调度日志发现显存分配正常没有超额分配。再看GPU监控发现显存使用率在5分钟内从60%飙到100%。查推理服务的请求量发现QPS在同时段翻了3倍。定位到根因超卖比例过高没有预留足够的缓冲应对突发流量。修复方案显存超卖比例从1.5倍降到1.2倍。增加显存水位线告警80%告警90%触发限流。推理服务增加请求队列超过队列长度时拒绝新请求而不是OOM。5.2 调度死锁当训练任务等不到资源另一个坑是调度死锁。场景一个训练任务申请4卡当前集群有3卡空闲训练任务排队等待。同时一个推理服务申请1卡看到有3卡空闲但Crater的调度策略是整卡分配推理服务需要等训练任务先分配。结果训练任务等第4张卡推理服务等训练任务释放互相等待死锁。这个问题本质上是调度器的资源预留机制没做好。修复方案引入资源预留概念训练任务排队时已经分配给它的资源会被预留不会被其他任务抢占。推理服务调度时跳过被预留的资源只看真正空闲的资源。增加超时机制训练任务排队超过30分钟自动降低优先级或缩减资源需求。5.3 GPU拓扑感知缺失导致的训练变慢这个坑最隐蔽。训练任务分配了4张卡但Crater没有感知GPU拓扑把跨NUMA的卡分给了同一个任务。结果卡间通信走PCIe而不是NVLink训练速度掉了30%。排查过程训练日志显示loss下降正常但吞吐量比预期低。用nvidia-smi topo -m查看拓扑发现4张卡分布在两个NUMA节点上。对比同规模任务的训练速度确认是拓扑问题。修复方案Crater增加GPU拓扑感知调度时优先选择同一NUMA节点内的卡。如果同一NUMA节点内卡不够再跨节点分配但会告警提示。训练任务配置里增加拓扑亲和选项强制要求同NUMA。5.4 磁盘IO争抢导致推理延迟抖动推理服务的延迟抖动很多时候不是GPU的问题而是磁盘IO被训练任务抢了。训练任务做checkpoint写入时磁盘IO会瞬间飙高推理服务读模型文件或写日志时被阻塞延迟从200ms抖到2s。修复方案磁盘IO分级推理服务的IO设为高优先级训练任务的IO设为低优先级。训练任务checkpoint写入限速避免瞬间打满磁盘。推理服务的模型文件预加载到内存避免运行时读磁盘。6. 训推一体化平台的日常运维监控、扩缩容与成本核算6.1 必须监控的四个核心指标训推一体化平台上线后日常运维需要盯住四个核心指标指标含义告警阈值处理动作GPU利用率卡上计算单元的实际使用率持续10分钟低于30%检查是否有碎片化触发碎片整理显存使用率显存池的分配率超过85%触发告警准备驱逐低优先级任务推理P99延迟推理服务的尾部延迟超过SLA的80%检查资源竞争调整配额训练任务排队时长训练任务从提交到开始运行的等待时间超过30分钟检查资源池容量考虑扩容这四个指标覆盖了算力利用率、资源健康度、服务质量、任务效率四个维度。缺一个都会导致盲区。6.2 扩缩容策略什么时候加卡什么时候加节点扩缩容的决策逻辑加卡当GPU利用率持续高于70%且显存使用率高于80%时说明单卡已经跑满需要加卡。加节点当单节点卡数已满且跨节点调度频繁时说明需要加节点。缩容当GPU利用率持续低于30%且显存使用率低于50%时可以考虑缩容。但缩容要谨慎因为训练任务的长周期特性缩容可能导致任务中断。我的经验是扩容易缩容难。扩容可以按需加缩容最好等训练任务自然结束后再操作。6.3 成本核算按任务类型分摊算力成本训推一体化平台的一个隐性价值是成本核算。以前训练和推理混在一起算力成本没法分摊。Crater的资源配额和监控数据可以精确到每个任务、每个租户的算力消耗。成本分摊模型训练任务按GPU卡时×卡型单价CPU核时×单价内存GB时×单价磁盘GB时×单价。推理服务按GPU卡时×卡型单价请求量×单请求成本。预处理任务按CPU核时×单价内存GB时×单价。这套模型跑下来每个团队每个月用了多少算力、花了多少钱一目了然。预算超了自动告警避免月底才发现账单爆炸。7. 写在最后一些个人体会这套AllDataCrater的训推一体化方案从选型到上线跑了大概四个月。中间踩的坑不少但回头看有几个判断是对的第一异构算力调度不能只靠K8s原生能力必须有一层专门的算力抽象。Crater这层抽象虽然增加了初期集成成本但后期调度灵活性的收益远大于成本。第二GPU切分要按场景选不能一刀切。MIG适合多租户推理vGPU适合开发测试整卡适合训练。选错了切分方式利用率反而会下降。第三监控比调度更重要。调度策略再完美没有监控就是盲调。四个核心指标必须盯住尤其是显存使用率和推理P99延迟。第四成本核算是推动平台持续优化的动力。当每个团队都能看到自己的算力账单时他们自然会优化任务配置减少浪费。如果你正在规划类似的平台我的建议是先从单节点、小规模跑通验证调度策略和监控体系再逐步扩展到多节点、多租户。不要一上来就搞大而全训推一体化的复杂度在于细节细节只能在实践中打磨。