恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
srt-slurm实战:GPU集群推理任务的编排与部署
首页
资讯中心
/
srt-slurm实战:GPU集群推理任务的编排与部署
srt-slurm实战:GPU集群推理任务的编排与部署
发布时间:2026/8/30 10:41:27
NVIDIA 开源的 srt-slurm 编排推理部署解决的不是“能不能在一张卡上跑推理”而是“多卡、多节点、多次提交的推理任务怎么被统一调度和编排”。它把 Slurm 的资源管理能力和上层推理状态管理组合在一起适合需要批量处理图像、文本、语音等模型的工程团队。最值得关注的点是这套思路把调度、容器、推理服务三者解耦部署时不容易变成一锅粥。我建议先不要急着找完整命令先把问题拆开你要处理的推理任务是什么类型需要跑多少条数据放在哪里输出怎么回收。等这些问题清楚后再看 srt-slurm 的编排层能不能接住你的流程。下面按实际落地顺序拆一遍。1. 先搞清楚 srt-slurm 到底编排了什么很多人一听“编排推理部署”会以为它只是把推理命令扔给集群去跑。实际上srt-slurm 这类方案要解决的是一整条链路输入数据怎么进、模型加载到哪个容器、GPU 资源怎么分配、任务失败怎么处理、输出结果怎么落盘、日志去哪看。Slurm 单靠自身也能提交作业但推理场景下我们还需要额外管理任务状态和失败重试。编排层就是补上这一段的。1.1 推理任务和训练任务不一样训练任务通常时间长、资源占用稳定、模型权重固定提交后可以几个小时甚至几天不用管。推理任务则完全相反单条耗时可能只有几秒但数量多、输入格式多样、偶发异常多还可能依赖预热的模型进程。如果在 Slurm 里直接提交“每次跑一条推理”的任务会出现几个常见问题每次提交都要重新加载模型GPU 利用率低。任务数量多但每个任务只占很小资源调度队列被刷屏。失败任务没有统一重试策略需要人工盯。输出文件命名容易冲突任务 ID 和输入 ID 对不上。srt-slurm 的编排层会把推理请求整理成带有状态的任务比如 pending、running、done、failed。只有状态为 done 的任务才认为成功failed 的任务可以按策略重试。这样 Slurm 还是做它擅长的事——分配 CPU、GPU、内存、节点而编排层负责把业务状态管理起来。1.2 编排器管状态Slurm 管资源部署时最容易犯的错误是把业务逻辑全部塞进 sbatch 脚本。比如在脚本里写复杂的输入解析、模型下载、结果入库、失败重试。这样看起来能跑但后面排查会很难受。正确的思路是分层Slurm 负责资源分配用哪个分区、几张 GPU、多少内存、排队优先级。容器负责环境隔离驱动可以不同Python 依赖不会互相污染。编排器负责任务流转从输入队列读取请求提交给 Slurm回收结果记录日志。这套分工的价值在于每一层都能独立替换。比如今天用 Slurm明天换成别的调度器编排层只需要改提交适配器今天用 Docker明天想换 Singularity容器层替换即可业务代码不用重写。2. 部署前先确认这套架构适合哪种环境不要一上来就搭多节点集群。先确认你手里到底有什么资源以及这套编排推理部署在你的环境里能不能跑通。原始材料里没有给出具体版本落地时一定先确认依赖版本和官方文档。2.1 硬件和系统条件srt-slurm 的典型运行环境是 Linux GPU 集群。至少需要一台装有 NVIDIA GPU 的服务器系统推荐 Ubuntu、Rocky Linux、Debian 这类主流发行版。Windows 可以开发调试但生产环境不建议因为 Slurm 和容器运行时的生态主要围绕 Linux。硬件方面先看三块GPU 型号和显存决定你能跑多大的模型、能不能开多实例。CPU 核数决定前处理、后处理和容错逻辑的吞吐。内存大小模型加载、批量推理、数据缓存都要吃内存。检查命令很基础但每次部署前我还会执行一遍nvidia-smi sinfo sbatch --versionnvidia-smi 用来确认驱动和 GPU 可见sinfo 用来确认 Slurm 分区sbatch --version 用来确认调度器主版本。这三个命令任何一个报错都先别往后走。2.2 容器和 GPU 运行时推理依赖很杂不同模型可能需要不同版本的 PyTorch、CUDA、cuDNN 或自定义算子。直接在宿主机上装换模型就很容易冲突。所以几乎都会引入容器方案。常见组合是Docker 或 Singularity 做容器运行时。NVIDIA Container Toolkit 让容器能访问 GPU。镜像里固定 CUDA、Python、推理框架版本。NVIDIA Container Toolkit 的核心作用是把宿主机驱动透传给容器。这里要注意容器里的 CUDA 版本不需要和宿主机的 CUDA 完全一致但宿主机驱动版本必须高于或等于容器内 CUDA 所需的最低驱动版本。否则会出现 CUDA 初始化失败、找不到 libcuda.so 之类的报错。如果只用单机手动装 Docker 加 Toolkit 就行。如果是 Kubernetes 集群可以看看 NVIDIA GPU Operator它把驱动、容器运行时、监控组件一起管理了。不过 srt-slurm 这种以 Slurm 为核心的场景重点还是先把 Slurm 和容器运行时连通。2.3 网络和存储需要考虑的点推理任务往往有大量输入输出文件存储设计比网络更早影响结果。如果你有共享存储比如 NFS、Lustre、GPFS那模型权重和数据集放共享路径会比较合适每个 Slurm 计算节点都能直接读取。共享存储注意几个判断点输入目录是否只读避免多个任务同时写入互相覆盖。输出目录是否按任务 ID 隔离建议统一结构比如outputs/{job_id}/{input_id}.json。模型文件是否过大加载时间是否超过任务超时时间。网络方面如果只是离线批推理节点间网络要求不高。但如果要把推理服务发布成 API就需要考虑端口管理、负载均衡、健康检查。这个在后面章节会展开。3. 最小可运行部署从单机单卡到多节点队列我始终建议先做最小验证再谈扩展。不要一上来就提交几百个任务也不要一开始就部署完整控制台。3.1 准备基础环境假设你已经有一台 Linux 服务器GPU 驱动正常接下来要做的事按顺序走安装 Slurm并配置一个默认分区。安装容器运行时和 NVIDIA Container Toolkit。准备一个推理镜像镜像里包含你的模型文件和推理脚本。确认 Slurm 作业脚本能调用nvidia-smi说明 GPU 透传成功。Slurm 的安装方式依赖你的发行版和网络环境这里不强行给固定命令。关键是先跑通一个最简单的 hello 作业srun --gpus1 nvidia-smi如果这条命令能打印出 GPU 信息说明 Slurm 调度、GPU 资源、驱动调用都通了。如果报错先看sinfo分区状态再看/var/log/slurm/下的日志。这一步很容易被跳过但跳过之后后面所有问题都会翻倍难排查。3.2 写一个最小推理作业脚本一个常见的 Slurm 作业脚本会包含资源申请和实际执行命令。下面是一个通用示例实际字段要以你的集群配置为准#!/bin/bash #SBATCH --job-namesrt-inference #SBATCH --outputlogs/%j.out #SBATCH --errorlogs/%j.err #SBATCH --gpus1 #SBATCH --cpus-per-task4 #SBATCH --mem16G #SBATCH --time00:30:00 srun python inference.py \ --input data/sample.json \ --output outputs/$SLURM_JOB_ID/sample.json这里有几个字段值得解释--output和--error是日志文件命名带上%j表示任务 ID防止多任务日志互相覆盖。--gpus1申请一张 GPU。--time00:30:00是超时时间推理任务一定要设防止死等。$SLURM_JOB_ID打印的是当前任务 ID用来拼输出目录很方便。为什么要把输出目录按任务 ID 隔离因为批量提交时多任务会并发运行如果大家都往results/result.json里写最后只会有一份覆盖后的结果。按任务 ID 隔离后每个任务写自己的目录后面做结果汇总时也更容易定位失败任务。3.3 先跑单条任务再扩大规模第一个验证只用一条样例数据不跑真实业务集。看三个东西任务是否从 pending 变成 running。日志里有没有加载模型、GPU 初始化成功的输出。输出文件是否存在且内容正确。单条任务跑通后再尝试数组作业。Slurm 的--array非常适合同类型批量推理sbatch --array1-10 run_array.sh脚本里通过$SLURM_ARRAY_TASK_ID对应不同输入文件#!/bin/bash #SBATCH --job-namesrt-array #SBATCH --outputlogs/%A_%a.out #SBATCH --errorlogs/%A_%a.err #SBATCH --gpus1 #SBATCH --cpus-per-task4 #SBATCH --mem16G #SBATCH --time00:30:00 srun python inference.py \ --input data/input_${SLURM_ARRAY_TASK_ID}.json \ --output outputs/${SLURM_ARRAY_TASK_ID}.json数组作业的好处是不用写循环提交命令调度器会管理每个子任务的状态。单个子任务失败不会阻塞其他子任务适合试批量。3.4 结果验证和日志检查任务结束后不要只看任务状态。Slurm 显示COMPLETED只能说明脚本退出了不能说明推理结果是对的。真正的成功标准是退出码为 0。输出文件存在且内容不是空文件。必填字段都有没有 NaN 或者错误占位符。日志里没有 CUDA error、OOM、模型加载失败等关键字。如果任务状态是FAILED第一个动作是看.err文件。常见问题包括路径打不开、模型文件权限不对、容器内没有 GPU 权限、输入 JSON 格式错误。排查顺序尽量固定不要每次从零开始。4. 推理任务编排的关键参数与扩展方式最小环境跑通后接下来才进入真正的编排阶段。这里的核心不是写更多脚本而是把参数和边界定清楚。4.1 并发、队列和优先级怎么取舍很多人在批量推理时会直接加大并发数。这个方向没错但要先理解并发增加后会带来什么。并发数升高意味着同时运行多个任务。每个任务都会申请 CPU、内存、GPU 显存和额外的模型加载开销。如果你有 8 张 GPU想同时跑 8 个推理任务每张卡都能分到这没问题。但如果你申请 16 个任务每个任务--gpus1那其中 8 个只能排队。排队本身不是坏事问题是任务一多单个任务等待时间变长失败重试也会更复杂。我从经验里总结一套比较稳妥的调整顺序先确认单任务需要多少显存和内存。用静态资源预估可以同时跑几个任务。从预估值的 50% 开始试。观察平均耗时、失败率、节点上的资源剩余量。再逐步增加直到某个指标明显恶化。Slurm 侧有几个参数会影响编排表现--gresgpu:N申请固定 GPU 数量。--qos限制优先级、最大运行时间和最大作业数。--partition把不同业务拆到不同分区。MaxArraySize控制数组任务数量上限。业务层也要做限流Slurm 的任务队列不是无限大。如果在编排器里一股脑提交几万个任务调度器可能不接受也会把日志和状态目录撑得很大。更常见的做法是分批提交比如每次 100 个子任务等结果回收后再提交下一批。4.2 GPU 显存隔离和多实例支持推理任务最敏感的资源是显存。两个模型同时放到一张卡上如果显存不够其中一个就会 OOM。处理思路有三种每任务独占整张 GPU最简单但可能浪费显存。用CUDA_VISIBLE_DEVICES指定不同任务使用不同 GPU适合单卡多任务的场景。用 MIG 或 vGPU 做物理隔离适合新机型但配置复杂度更高。MIG 的全称是 Multi-Instance GPU可以把一张物理 GPU 切成多个实例每个实例有独立的显存和计算切片。如果模型不大MIG 能明显提高 GPU 利用率和稳定性。但要注意 MIG 需要对驱动和容器运行时有额外支持不是所有卡都支持也不是所有镜像都兼容。判断标准很简单如果一个任务崩溃会影响其他任务说明隔离不够如果需要反复调整显存大小才能稳定跑说明资源申请和实际模型占用不匹配。4.3 把离线任务变成推理服务离线批处理只是 srt-slurm 编排的一种形态。实际生产里很多团队还需要把模型发布成 HTTP API供业务系统调用。这种情况不能每个请求都提交一个 Slurm 任务因为任务排队和容器启动时间根本扛不住。更合理的做法是在 Slurm 集群上启动一组常驻推理服务实例。每个实例占用固定 GPU 资源运行同一个模型服务。编排器负责探测实例健康状态。外部请求通过负载均衡转发到健康的实例。一个简化版的 Slurm 常驻服务脚本可以是这样#!/bin/bash #SBATCH --job-namemodel-api #SBATCH --outputlogs/%j_api.log #SBATCH --errorlogs/%j_api.err #SBATCH --gpus1 #SBATCH --cpus-per-task4 #SBATCH --mem16G #SBATCH --time08:00:00 srun python serve_model.py \ --port $SLURM_JOB_ID \ --model /models/bert-base这里端口用任务 ID 起名主要是为了测试时避免冲突。生产环境通常不会这样设计而是由一个服务注册中心来分配端口并登记实例地址。把离线任务变成服务后编排层要关注的参数就变了原来关心超时和重试次数现在还要关心健康检查间隔、优雅退出、请求超时、并发上限。Slurm 还是负责保证实例跑在正确的 GPU 节点上但请求路由逻辑应该由编排层或网关来处理。4.4 多模型、多租户和配额当团队多人共用集群时光有 Slurm 资源限制还不够。你需要给不同业务、不同用户做配额。比如A 组是图像模型只能使用 A 节点。B 组是用户在线请求需要较高优先级。C 组是离线数据处理只在夜间批量执行。Slurm 的分区、QoS、账户配额可以做第一层隔离。编排层则要维护“哪个项目组提交了哪些任务”并提供按项目查看任务统计和失败情况的入口。如果这一步不做后面排查问题时会分不清某个失败的 GPU 任务是属于哪个业务方。多模型场景下模型文件的管理也很关键。每个容器镜像尽量只包含一个模型或同一系列模型避免因为模型文件过大导致镜像拉取时间过长。镜像 tag 建议带版本号比如inference/bert:v1.2.0不要用latest否则重复调度时可能加载到不同权重结果不可复现。5. 实际部署中容易踩的坑这部分是我最想写的。因为 srt-slurm 这类编排方案功能上看着简单真正跑起来会遇到不少环境层面的问题。5.1 启动失败大概率不是模型问题很多人在容器启动失败后第一反应是检查推理代码。但实际最常见的问题集中在三个方面路径和权限模型文件不存在或当前用户没有读取权限。容器 GPU 透传失败容器里执行nvidia-smi报错。CUDA 和驱动不匹配容器内 CUDA 版本要求比宿主机驱动支持更高。排查顺序可以先看.err日志再手动在容器里执行一次同一命令docker run --rm --gpus all inference/bert:v1.2.0 nvidia-smi如果这条命令能显示 GPU说明容器、驱动、Toolkit 都正常。如果这条命令失败那问题根本不在模型而是容器运行时没有把宿主机的 GPU 设备暴露进去。这里不要急着改代码。先把容器能跑通、GPU 能识别、模型文件能读取这三件事逐项验证再回到业务脚本。5.2 任务卡住先看资源占用和日志任务卡住比报错更难查。报错至少给了线索卡住可能只是 pending 状态也可能已经 running 但什么都没输出。我的排查顺序一般是看任务当前状态squeue。看日志文件大小和最后修改时间。看节点资源占用nvidia-smi和top。看输出目录是否被创建。如果任务一直 pending不是它卡住了而是没有可用资源。可以先看是不是别的大任务占了整张卡或者 QOS 限制了最大排队数。如果任务是 running 但长时间没有输出可能是模型正在加载也可能是输入数据解析进入了死循环。这时再看 CPU 和显存占用CPU 占用高说明在计算显存占用高说明模型已加载如果两边都没变化大概率在等某个网络请求或锁。在容器里跑长任务时要特别注意临时目录空间。推理过程中如果输出文件很大而/tmp或容器挂载路径空间不足任务会表现为写入变慢甚至卡死但日志不一定有明确报错。5.3 版本兼容和升级顺序NVIDIA 生态的版本兼容问题会反复出现尤其是驱动、CUDA、容器运行时、Slurm 之间。升级时最容易踩的坑是只升级一个组件其他组件没有配套。我建议把版本记录下来并放到镜像描述或集群文档里。至少记录这几项宿主机 NVIDIA 驱动版本。容器内 CUDA 版本。NVIDIA Container Toolkit 版本。Slurm 版本。推理框架版本比如 PyTorch 或 TensorRT。升级顺序上先做兼容性验证再操作生产环境。可以准备一个“冒烟测试任务”里面包含一个最小模型、一条样例数据、一个断言语义检查。每次升级驱动、镜像或 Slurm 配置后都先跑一次冒烟测试任务。这个冒烟测试任务不应该等到生产任务失败时才想起来。平时也可以作为定时任务定期验证整个编排链路是否健康。6. 我的落地建议最后说说我自己的判断。这套方案不是适合所有人但如果你正好在 GPU 集群上长期跑批量推理很值得把编排思路拿过去用。6.1 学习阶段怎么试学习阶段不要从多节点开始。先在一台机器上把 Slurm 装好创建一个分区跑一个最简单的 Python 睡眠任务#!/bin/bash #SBATCH --outputlogs/test.out #SBATCH --errorlogs/test.err srun python -c print(hello srt)能跑通后再把任务改成 GPU 任务加上容器。不要一开始就追求美观的控制界面先把任务提交、日志、输出回收这三条链路走通。如果你以前只用过单机脚本第一次用 Slurm 时觉得不适应很正常。重点不是熟悉所有参数而是理解“申请资源”和“执行命令”之间是被调度器拆开的。写脚本时把资源申请放上面把执行逻辑放下面后面维护会轻松很多。6.2 生产阶段怎么收敛如果正式业务要用我建议提前定义好以下几套规范任务 ID 规范统一使用任务 ID 关联输入和输出。输出目录规范比如outputs/{任务ID}/。日志目录规范统一收集到共享目录方便检索。失败重试规范哪些任务允许重试重试次数上限是多少。镜像版本规范每个模型单独一个 tag禁止无 tag 镜像。生产阶段还要考虑一个容易被忽略的点任务积压时的告警。如果编排器提交任务后Slurm 队列越来越长新任务等待时间超过预期需要有告警。否则用户可能以为任务在跑实际一直排队。6.3 判断这套方案是否适合你适合采用 srt-slurm 编排推理部署的场景通常有几个共同特征推理任务足够多但不是单请求实时响应。有多个用户或项目组共享 GPU 资源。需要保留任务执行历史方便回溯。输入输出以文件形式批量产生。需要在多台 GPU 节点上统一运行同一套推理逻辑。如果你的业务主要是在线请求延迟要求毫秒级那基于 Slurm 的批处理调度不是最合适的方向。在线服务更适合用 Kubernetes 推理框架自带的服务化模块比如 Triton Inference Server配合自定义路由。如果只是单机跑一个模型也不需要编排直接写好 Python 脚本调用就行。编排和调度是给“规模和复杂度到了一定程度”的场景准备的能力。单机场景硬上 Slurm只会增加维护成本。踩过几次之后我发现很多问题不是工具能力不够而是前置环境和输入材料没有处理干净。srt-slurm 编排推理部署真正考验人的地方不是调度器配置而是对业务任务的抽象能力。你能把任务边界定义清楚这套方案才能发挥价值定义不清楚再好的编排工具也会变成新的麻烦来源。