ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于Slurm的推理编排:从单机脚本到GPU集群调度实践

基于Slurm的推理编排:从单机脚本到GPU集群调度实践 很多人第一次接触“编排推理部署”这个词是在看到 NVIDIA 开源了一个叫 srt-slurm 的项目之后。第一反应通常是两个srt-slurm 是什么我单机跑推理不是挺好的吗为什么要学一套新的调度系统我现在的判断是这种工具真正要解决的不是“把一条推理代码跑起来”而是把一堆需要 GPU 的推理任务变成可排队、可调度、可追踪、可复现的集群级流程。对你一个人调试代码它可能显得重但如果你在一个团队里有多个模型、多块 GPU、多批输入数据、多个实验同时进行单靠“谁手里有空卡就手动跑一下”的办法迟早会乱成一锅粥。这篇文章我就围绕 srt-slurm 这类基于 Slurm 的推理编排方案聊清楚几个问题它到底解决什么适合谁怎么从单机脚本迁到调度器上以及真实落地时最容易在哪些地方翻车。1. 先搞清楚这类“编排推理部署”到底解决什么问题1.1 单机脚本能跑不等于团队推理效率高假设你有一个已经训练好的模型输入是一批文本或图片需要批量做推理把结果保存下来。个人场景下这个过程很简单写一个 Python 脚本遍历目录调用模型保存输出然后喝杯咖啡等它跑完。但换成团队场景事情就变味了。比如你有十个人每个人手里都有推理任务公司有八块 GPU但分布在两台或三台机器上。很多人会先检查一下哪块卡是空闲的然后 SSH 上去自己写个脚本跑。问题马上出现两个人同时看到同一块卡空闲都跑上去了显存不够互相影响。有人跑了个大任务把整张卡占满其他人的小任务只能等着。任务跑完了结果散布在不同机器的临时目录里没人知道哪个文件对应哪个实验。有人想跑一个需要 80G 显存的模型但当前空闲的卡只有 48G他只能挨个试直到找到合适的卡。这些问题不是模型本身的问题而是“任务调度”的问题。你要做的不是写更好的推理代码而是把 GPU 看作公共资源让任务排队、按需申请、释放后自动分配给下一个。1.2 Slurm 的用武之地不是抢 GPU而是管理队列和优先级Slurm 是高性能计算领域最常用的作业调度器之一。它最擅长的事情就是把计算任务Job放到计算节点Node上执行并且根据用户提交的硬件申请CPU、内存、GPU 数量来安排资源。很多人对 Slurm 的误解是它只是给高校和超算中心用的我们跑 AI 推理用不上。但实际上只要你有超过一台带 GPU 的机器、有多个需要重复运行的任务Slurm 就能帮你建立一套清晰的管理秩序。它解决的核心问题可以概括为任务不再直接抢占机器而是先进入队列。提交任务时明确申请多少 GPU、多少内存、多少 CPU调度器按照分区和优先级来分配。你可以随时查看排队情况、运行状态、历史记录。任务输出可以统一重定向到日志文件不再散落各处。所以当我看到 NVIDIA 开源 srt-slurm 这类项目时我的第一反应是它想把 AI 推理任务也变成 Slurm 调度下的一等公民让推理部署不再是“每个人手动找卡、手动跑脚本”的游击战。2. srt-slurm 的出现把推理任务放到了调度器视野里2.1 从项目命名看它想做哪一层的事srt-slurm 这个项目名由两部分组成srt 和 slurm。srt 的具体含义目前公开资料里没有非常明确的统一解释有人猜是 Slurm-based Runtime/Resource/Task 的缩写也有人说是某个推理服务项目的简称。我认为重要的是后半部分——slurm。这基本说明它是在 Slurm 生态里做推理编排部署的工具。在常见实践中这类项目通常会在 Slurm 之上做一层“推理作业包装”让你不需要直接拼接 Slurm 命令和推理脚本而是通过一个更上层的配置文件或命令行方式定义推理任务需要的模型、输入数据、GPU 资源、输出路径然后由工具自动生成 Slurm 作业并提交。这就像把一个复杂的 Shell 命令流程封装成一套标准模板。你交给它的不是“启动命令”而是一份任务说明。它负责跟调度器打交道把资源申请、任务提交、日志收集这些环节接住。2.2 它是怎么和 NVIDIA GPU 生态配合的NVIDIA 开源的推理编排方案通常不会单独存在而是会围绕自家生态设计。常见的配合方式包括使用 NVIDIA Container Toolkit 让容器能够访问 GPU。使用 CUDA/cuDNN/TensorRT 作为推理后端。通过 NVIDIA 的模型推理框架例如 Triton Inference Server提供在线服务能力。在大规模推理场景下利用 Slurm 的--gresgpu参数申请指定数量的 GPU。如果一个推理编排工具叫 srt-slurm它大概率利用了 Slurm 对 GPU 资源的直接管理能力同时把 NVIDIA 栈里的驱动、运行时和模型服务组件接入调度流程。这里要提醒一点如果你准备部署某个叫 srt-slurm 的项目不要只看标题一定要先到仓库里确认它的依赖要求、支持的 CUDA 版本、是否要求特定驱动版本以及是否必须搭配 NVIDIA Container Toolkit。不同版本的组合经常不兼容这是排错时最容易忽略的一层。3. 上手路径从单机跑通到 Slurm 集群编排3.1 先准备一套可用的 Slurm 环境如果你只有一个单机环境也可以先让 Slurm 跑起来。Slurm 支持在同一台机器上配置一个控制节点加一个计算节点。这样你不需要先搭真实集群就能练习“提交任务、查看队列、获取结果”这套流程。一个最小环境通常包含一台 Linux 服务器推荐 Ubuntu 20.04 或 22.04。已安装 NVIDIA 驱动。已安装 CUDA、cuDNN 或你模型所需的推理运行时。已安装 Slurm。多数发行版可以通过包管理器安装但在生产环境更建议从源码或官方仓库构建匹配版本。如果用到容器还需要安装 NVIDIA Container Toolkit。这类工作最大的坑是 Slurm 版本和 munge 认证配置不一致。Slurm 用 munge 进行节点间认证控制节点和计算节点的 munge key 必须一致否则一提交作业就会报错。第一次搭环境时建议先跑sinfo确认节点是idle状态再跑srun hostname验证最简单的任务能执行。3.2 把一次推理脚本包装成可提交的作业假设你已经有一个推理脚本run_inference.py它接收输入目录和输出目录两个参数。在 Slurm 环境中你需要把这个脚本放到一个作业脚本里像下面这样#!/bin/bash #SBATCH --job-namemy_inference #SBATCH --partitiongpu #SBATCH --gresgpu:1 #SBATCH --cpus-per-task8 #SBATCH --mem24G #SBATCH --time02:00:00 #SBATCH --outputlogs/%x_%j.out #SBATCH --errorlogs/%x_%j.err python run_inference.py \ --input /data/inputs \ --output /data/outputs这里有几个参数需要实际理解而不只是抄走--partitiongpu是指定分区分区相当于资源池你要确保你的 GPU 节点被划到了这个分区。--gresgpu:1是申请一块 GPU。如果你的机器上有多种 GPU也可以写成--gresgpu:rtx4090:1来指定类型但前提是节点配置了对应 gres。--time是最长运行时间。推理任务不像训练任务时间固定最好结合历史耗时预留缓冲设置太短会导致任务中途被杀掉设置太长会影响调度器安排。--output和--error建议用%x任务名和%jJob ID展开避免不同任务写同一个文件。如果你是第一次从一个裸脚本迁移到 Slurm我建议你先用一条非常小的输入跑一遍确认整个流程能走通再提交真正的批量推理任务。这里不要嫌慢因为你很快会发现如果作业提交失败排查问题的成本远高于在本地多跑几遍。3.3 用“先跑通、再排队、后批量”的顺序验证一个比较稳妥的上手顺序是在登录节点上直接运行推理命令确认模型能加载、推理能出结果。把命令写进 Slurm 作业脚本提交一个最小测试作业。查看作业日志确认输出路径和本地一致。用 5 到 10 条输入数据做批量测试。最后再提交完整数据集并观察 GPU 利用率和排队时间。这个顺序的核心逻辑是先缩小变量范围。如果第一步失败问题多半在模型或运行时如果第二步失败问题多半在 Slurm 配置或资源申请如果第三步失败多半是路径或权限如果第四步失败再考虑批量逻辑和并发问题。不要一开始就把几百个文件塞进去跑一旦报错你很难分清是模型的问题、脚本的问题还是调度配置的问题。4. 真正投入使用时最容易出问题的不是模型而是这些环节4.1 资源请求和实际 GPU 分配的匹配Slurm 允许你申请 GPU但申请到 GPU 不代表你能直接用。你需要确认节点上的驱动、CUDA 库、容器运行时都正常。更常见的问题是申请了 2 块 GPU但你的代码没有设置CUDA_VISIBLE_DEVICES结果两个进程还是共用第一块卡造成显存溢出另外一块卡却闲着。在 Slurm 作业里环境变量CUDA_VISIBLE_DEVICES通常已经被调度器自动设置好了。但如果你在脚本里手动覆盖了它或者用了torch.cuda.set_device()之类的调用就要特别小心。我建议在作业脚本开头打印一下这个变量echo CUDA_VISIBLE_DEVICES$CUDA_VISIBLE_DEVICES这样至少能第一时间确认任务实际看到的 GPU 编号和调度器分配的是一致的。还有一个容易忽略的点--mem申请的是内存而不是显存。很多人在推理任务上内存申请过多导致排队时间变长或者申请过少导致任务 OOM。你需要根据模型的大小和 batch size 估算而不是拍脑袋。4.2 容器环境、驱动版本和路径隔离如果你在 Slurm 里用容器跑推理比如通过srun调用nvidia-docker或apptainer那就要额外注意几个问题宿主机驱动版本需要满足容器的 CUDA 运行时要求。容器内路径和宿主机路径要映射清楚。容器默认可能没有挂载你的模型目录和数据目录。多节点并发时不建议所有节点把大量中间结果写到共享目录的同一路径下容易互相覆盖。我的经验是尽量把“数据读取”和“结果写入”这两件事独立出来。比如约定一个统一的数据目录结构/data/projects/实验名/input/ /data/projects/实验名/output/ /data/projects/实验名/logs/每次提交任务时都把这些路径作为作业参数传入而不是在代码里写死。这样无论是单机验证还是集群批量跑逻辑都一致排查问题的时候也容易定位。4.3 日志、输出和失败重试推理编排项目能长期用下去靠的不是第一次跑通而是每次跑完都能回答三个问题任务跑了吗跑得怎么样结果在哪里在 Slurm 里有squeue查看排队和运行状态有sacct查看历史记录有scontrol show job jobid查看详细调度信息。如果作业失败了先从这些地方找信息然后再去日志文件里看具体报错。真正麻烦的是批量推理任务中有几条数据失败。常见的处理方式有脚本内部对每条数据单独 try/except把失败记录写到一个 failed 列表里。任务结束前打印失败数量和失败文件路径。作业脚本里允许失败后退出码不为 0方便调度器记录。再提交一个“重跑失败项”的作业而不是重新跑整个数据集。如果你正在设计自己的推理部署方案一定要把失败重试这个环节提前考虑进去。很多人第一个版本只写成功路径等真正跑了 10 万条数据才发现中间有几百条因为输入格式或内存问题挂了但整个任务早就退出了数据没有持久化只能从头再来。5. 和 Kubernetes 编排相比srt-slurm 适合哪条路线5.1 在线推理服务更依赖 K8s 生态系统现在很多推理部署方案都围绕 Kubernetes 展开模型以微服务的方式常驻运行通过 Service 和 Ingress 暴露 API支持自动扩缩容。这种模式适合在线推理用户请求随时到达服务需要持续响应延迟要求高流量波动大。K8s 的优势在服务治理滚动更新、负载均衡、健康检查、弹性伸缩这些都是常驻服务需要的。但 K8s 的复杂度也高更重要的是它对“排队调度”这件事并不擅长。如果你有一个耗时很长的批量推理任务需要排队等待 GPU 资源K8s 的默认调度器不会像 Slurm 那样提供一套完整的优先级、抢占和回溯机制。5.2 离线批量推理和实验调度更适合 Slurm 的思路Slurm 的思路更像一个“任务银行”你把任务提交进去它按照策略分配资源执行结束后清理资源并保留记录。这种模型非常适合一次跑几十万张图片的批量推理。同一模型在多个数据集上做评测。多个实验并行每个实验需要不同数量的 GPU。需要按用户或项目配额限制 GPU 使用量的场景。NVIDIA 选择把 srt-slurm 开源合理的判断是它发现很多 AI Lab 和内部基础设施团队已经用 Slurm 管理训练资源但推理任务还停留在各自为战的状态。把推理也接入 Slurm可以让训练和推理共用同一套资源池避免“训练节点吃满推理节点闲置”的资源割裂。5.3 不要纠结选谁先判断任务形态如果你要接一个高并发的在线 API那 K8s 更合适如果你要跑一批离线任务体验一次提交、排队、批量完成那 Slurm 更贴合如果你的场景是“既要在线上服务又要做批量实验”那么更现实的架构是两者共存在线服务走 K8s批量推理和实验调度走 Slurm。这个问题没有标准答案只有匹配不匹配。你团队里谁更熟悉容器生态谁更熟悉高性能计算调度运维成本控制在什么程度这些都可能改变你的选择。想在两个生态之间强行二选一反而会放大学习成本。6. 给新手的几条建议把编排这件事想成沉淀标准流程6.1 不要太早优化调度策略第一次使用 srt-slurm 或类似方案时不要一上来就研究优先级、抢占、多分区。先把最简单的流程跑通比如用一个作业脚本申请一块 GPU运行一个很小的推理脚本输出一个文件。确认这个链路可靠之后再逐步增加批量数据的规模、多个 GPU 的申请、多个分区的配置。很多新手的误区是觉得调度器难是因为不懂里面的高级参数。实际上真正让项目推进不下去的往往是基础环节没打通驱动不兼容、路径不一致、日志输出混乱。先把这些基础打牢高级策略只是锦上添花。6.2 把推理任务当作“可复现流程”来设计一个推理任务除了模型和输入数据还应该包含完整的运行环境信息Python 版本、CUDA 版本、关键依赖版本、推理框架版本、GPU 类型和数量。如果你只用“在我电脑上能跑”来交付一个任务那到了调度器上一定还会出问题。更好的做法是用一个固定的环境构建文件来记录这些依赖。比如 Python 的requirements.txt或environment.yml再加上一个 README 说明推荐的驱动和 CUDA 版本。这样无论任务在个人电脑上跑还是提交到集群上跑环境差异都在可控范围内。6.3 一个可以参考的三步框架面对 srt-slurm 这类工具建议新手按下面这个框架推进第一步单机化。先把推理脚本、数据路径、结果输出全部整理清楚让它在单机上可以重复运行。第二步容器化。把运行环境固化下来确保换一台机器也能复现同样的结果。第三步编排化。在第一步和第二步都稳定之后再引入 Slurm 做任务提交、排队和资源管理。这个顺序的优先级是先解决“能不能跑”再解决“换个环境能不能跑”最后解决“很多任务同时跑还乱不乱”。很多人直接跳到第三步结果环境问题、路径问题、依赖问题混在一起排查起来非常痛苦。回到开头的问题srt-slurm 到底是干什么的我的理解是它不是一个帮你调模型的工具也不是一个加快推理速度的神器。它更像是一座桥梁把“GPU 推理任务”和“高性能调度系统”连起来让推理工作从个人脚本变成团队基础设施的一部分。如果你只是在一个 Colab 或单张显卡上调试模型你暂时不需要它。但如果你在一个有 GPU 集群、多个人协作、一大批推理任务需要稳定运行的团队里你就值得花时间研究它。因为单次跑通只是开始真正有价值的是让每一次推理都能按标准流程执行、被记录、可追溯、可重试。这才是编排的意义。
返回列表