尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

从Slurm到推理编排:打通GPU资源调度与模型服务最后一公里

从Slurm到推理编排:打通GPU资源调度与模型服务最后一公里 如果把一个深度学习模型的部署当成“把容器跑起来”那大部分推理项目其实早该上线了。真正拦住你的往往不是模型权重不是推理框架而是下面这个问题集群里有几十块 GPU但谁的任务在哪个节点、哪张卡上跑由谁来安排很多团队的实际状态是训练和推理共享一批 GPU资源申请靠线下沟通卡被谁占满要靠挨个ssh上去看nvidia-smi。一个新模型要上线得先人工找到一台不太忙的节点手动起容器手动记端口进程一断只能靠运维半夜爬起来。这种模式下模型的迭代速度很快但上线速度永远卡在资源协调上。所以最近 NVIDIA 开源相关推理编排项目时大家关注的重点往往不是“又一个调度器”而是它把推理服务的生命周期管理和集群调度真正打通了。这类项目以srt-slurm为代表的方向本质上是在解决推理部署的“最后一公里”让一个推理任务像提交作业一样简单让 GPU 分配、容器启动、模型加载、服务暴露和状态观测全部自动化。这篇文章不会只停留在概念层面。我会从推理编排的痛点讲起说明 srt-slurm 这类方案在技术栈中的定位然后用一套完整的 Slurm NVIDIA Triton 推理服务示例演示从集群配置、任务提交到推理接口验证的全过程。文章会覆盖环境准备、配置文件、常见报错和运维最佳实践适合正在搭建内部推理平台的算法工程师、平台开发者和运维同学收藏备用。1. 推理部署为什么需要编排先看一个典型场景。假设团队里有 6 台 GPU 服务器每台 4 张 A100总共 24 张卡。训练任务占用一部分在线推理占用一部分还有临时的算法实验经常“借卡跑一下”。如果没有统一编排会遇到几类典型问题。第一资源利用率完全依赖人的判断。有人习惯把任务固定提交到某台节点哪怕那台节点的 GPU 已经排满另一边某些空闲节点却整晚没人用。等真正需要大规模推理时最先爆掉的不是模型性能而是人工排卡的效率。第二部署动作很难标准化。A 同事上线模型用docker run手动挂载参数B 同事写成 systemd 服务C 同事直接在物理环境 conda 里跑。每个人的启动方式不同日志位置不同环境变量不同排查问题时要重新学习一套“约定”。第三GPU 资源没有隔离边界。一个任务在容器里执行nvidia-smi能看到所有显卡如果不小心设置了错误的CUDA_VISIBLE_DEVICES很可能一次实验就把整个节点显存打满影响同节点的其他服务。换一个角度理解训练任务天然适合排队因为训练的时间维度以小时甚至天为单位晚一点开始影响不大。但在线推理服务对响应时间和稳定性更敏感它需要的不是“等待排到”而是“在指定节点、指定 GPU、以可重复的方式快速拉起”同时还要能被监控、被健康检查、被优雅下线。这就是推理编排要解决的问题。它不是要把一个推理框架再封装一遍而是把“资源分配”和“服务运行时”这两层结合在一起。用户只需要告诉集群我要一个什么样的推理任务、需要几块 GPU、用哪个镜像剩下的事情——选节点、分配 GPU、起容器、映射端口、上报状态——交给编排层自动完成。2. 从资源调度到推理编排srt-slurm 的定位说起资源调度很多做平台开发的同学第一反应是 Kubernetes。这两年 K8s 在模型推理领域的接受度确实在提高但有一个事实需要注意在很多以科学计算和深度学习起家的高性能计算中心Slurm 仍然是整个集群的调度底座。Slurm 是开源的高性能计算工作负载管理器广泛用于管理集群中的计算节点、GPU 资源和作业排队。它本身的模型非常成熟用户用sbatch或srun提交作业Slurm 负责根据分区、队列、资源和优先级决定作业在哪些节点上运行并负责资源隔离和作业生命周期管理。但 Slurm 并不是天然的“推理部署平台”。它擅长的是把一个作业调度到资源上跑完而在线推理服务通常需要长期驻留、需要提供 HTTP/gRPC 接口、需要对模型版本进行管理、需要自动重启。这些能力不是 Slurm 的开箱即用功能需要有人在上层做一层设计。NVIDIA开源的 srt-slurm 方向看名称就能猜到它的技术路线以 Slurm 作为资源调度底座把推理运行时如 NVIDIA Triton Inference Server的部署动作封装成可编排的作业。它不是要把 Slurm 改造成 K8s也不是要在 K8s 里模拟一个 Slurm而是在现有 Slurm 集群上补足推理服务需要的“服务化”能力。从架构定位上看这类方案和 Kubernetes 方案的区别可以总结为维度Kubernetes 方案Slurm srt-slurm 方案调度模型面向容器和微服务面向作业和资源分配资源划分Pod 级别依赖 Device PluginNode GRES GPU 卡粒度天然适合 HPC服务发现Service Ingress 较完善需要额外设计端口映射和服务注册推理任务适配标准但需要较多 YAML 编排贴近现有深度学习团队使用习惯团队上手成本需要理解 Pod、Service、PVC 等概念对 HPC 用户几乎零成本对已经在使用 Slurm 的团队来说这类方案最大的价值是不用推翻已有的集群体系。用户提交推理任务的方式和提交训练任务一样调度层共用同一套资源和账号体系运维也不用同时维护两套调度系统。需要说明的是srt-slurm 这类项目仍处于快速迭代阶段不同版本的具体命令和接口可能会有变化。本文后续不会逐条猜测细节而是把侧重点放在整个推理编排链路上无论项目怎么更新你需要打通的环节——GPU 资源识别、容器运行时、作业提交、端口管理、健康检查——是稳定不变的。3. 环境准备与前置条件要把推理编排真正跑起来至少需要准备三类环境GPU 节点的驱动和 CUDA、容器运行时、Slurm 集群。下面按顺序说明。3.1 操作系统与 GPU 驱动GPU 驱动是推理环境的地基。驱动装不上后面所有环节都无从谈起。以 Ubuntu 系统为例安装驱动之前建议先确认自己需要的 CUDA 版本再反向选择驱动版本。如果你只是跑推理服务而不是训练大模型通常不需要安装完整的 CUDA Toolkit因为 NVIDIA 官方推理镜像里已经自带了 CUDA 运行库。宿主机只需要有和镜像兼容的 GPU 驱动即可。安装驱动的方式一般有三种通过系统包管理器安装 NVIDIA 驱动例如apt install nvidia-driver-xxx通过nvidia-detect或ubuntu-drivers devices查询可用驱动版本手动从 NVIDIA 官网下载.run文件安装风险较大需要先禁用默认的 nouveau 驱动不建议新手使用。安装完成后用nvidia-smi验证nvidia-smi预期输出会列出 GPU 型号、驱动版本和 CUDA 版本。最小可用的确认标准是能看到 GPU并且驱动版本满足推理镜像的要求。3.2 容器运行时与 NVIDIA Container Toolkit推理服务建议统一用容器交付。在 GPU 节点上Docker 默认无法直接访问 GPU必须安装 NVIDIA Container Toolkit把 NVIDIA Container Runtime 注册给 Docker。安装步骤以 Ubuntu/Debian 为例# 根据系统信息添加 NVIDIA Container Toolkit 软件源 distribution$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | sudo tee /etc/apt/sources.list.d/libnvidia-container.list # 安装并配置运行时 sudo apt-get update sudo apt-get install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtimedocker sudo systemctl restart docker注意不同发行版和不同 Docker 版本的命令可能有差异。如果你使用的是 containerd 而不是 Docker需要把--runtimedocker替换为 containerd 对应的 runtime。配置完成后可以用一个小容器验证 GPU 是否透传成功docker run --rm --gpus all nvidia/cuda:11.8-base-ubuntu22.04 nvidia-smi3.3 Slurm 集群Slurm 需要部署在管理节点和计算节点上。完整部署一套 Slurm 涉及 munge 认证、slurmctld 管理进程、slurmd 计算节点进程和 slurmdbd 计费数据库等组件。这个流程本身可以单独写一篇文章这里只强调几个与 GPU 推理编排强相关的点所有节点必须使用统一的网络通信机制建议配置 munge 认证/etc/slurm/slurm.conf是所有节点的核心配置计算节点需要启动slurmd管理节点需要启动slurmctld配置修改后需要重启相关进程或使用scontrol reconfigure重新加载。如果当前还没有 Slurm 环境可以先在一台多卡机器上搭建“单节点集群”也就是控制节点和计算节点都是同一台机器。这样既能验证 GPU 资源识别也能把编排流程完整跑通适合做最小实践。4. 集群配置让 Slurm 认识 GPUSlurm 本身不会自动感知节点的 GPU需要手动在配置里声明。这是最容易踩坑的一步很多节点明明有 GPU但提交带--gresgpu的作业时永远 PENDING就是因为配置里没有告诉 Slurm 这张卡存在。4.1 在 slurm.conf 中声明节点与分区假设我们有node01到node04四台节点每台 4 张 GPU用于推理任务的节点可以单独放到一个分区里。# /etc/slurm/slurm.conf 关键片段 NodeNamenode[01-04] Gresgpu:4 CPUs32 StateUNKNOWN PartitionNameinfer Nodesnode[01-04] DefaultYES MaxTimeINFINITE StateUP这里的含义是NodeName声明节点列表Gresgpu:4声明该节点有 4 个 GPU 资源CPUs32声明可用 CPU 核数PartitionNameinfer定义一个名为infer的分区后续推理任务都提交到这个分区。4.2 在 gres.conf 中定义 GPU 文件Slurm 4.x 系列使用gres.conf来定义 GPU 设备文件。如果节点名和 GPU 编号规则一致可以这样写# /etc/slurm/gres.conf NodeNamenode[01-04] Namegpu File/dev/nvidia[0-3]对于较新的 NVIDIA GPU也可以使用CTypeGPU之外更精细的资源配置例如 MIG 切片NodeNamenode01 Namegpu File/dev/nvidia0 CTypeGPU NodeNamenode01 Namegpu File/dev/nvidia1 CTypeGPUMIG 场景下的配置更复杂且不同模型差异很大建议先跑通完整链路后再深入。4.3 验证 GPU 资源是否被识别重启或重载配置后使用以下命令检查sinfo -o %n %G %P scontrol show node node01 | grep -i gres如果看到类似Gresgpu:4的输出说明 Slurm 已经正确识别 GPU 资源。此时再提交一个交互式作业测试srun --partitioninfer --gresgpu:1 nvidia-smi这个命令会申请一块 GPU 并在对应节点上执行nvidia-smi。如果输出正常说明 GPU 资源已经被调度器分配这是推理编排流程真正能跑起来的前提。5. 用 srt-slurm 提交推理任务在 Slurm 的调度模型里推理服务可以看作一个需要长期运行的作业。它的核心逻辑很简单申请一块 GPU启动一个容器容器内运行推理服务对外暴露端口。下面以 NVIDIA 官方的 Triton Inference Server 为例演示一条完整的推理编排链路。5.1 准备模型仓库Triton 通过模型仓库识别和加载模型。模型仓库是一个特定目录结构每个子目录代表一个模型模型版本放在以数字命名的子目录里。一个典型的结构如下model_repository/ ├── text_encoder/ │ ├── 1/ │ │ └── model.plan │ └── config.pbtxt └── ensemble/ ├── 1/ └── config.pbtxtconfig.pbtxt用文本协议描述模型名称、输入输出张量、后端类型和运行实例数。例如name: text_encoder platform: tensorrt_plan max_batch_size: 8 input [ { name: input data_type: TYPE_INT32 dims: [128] } ] output [ { name: output data_type: TYPE_FP32 dims: [512] } ] instance_group [ { count: 1 } ]这一步决定了推理服务能做什么也决定了后续部署验证是否有意义。实际生产环境中模型仓库建议放在共享存储上这样多个节点可以共用一套模型文件方便版本更新。5.2 编写推理作业提交脚本用sbatch提交一个作业脚本让 Slurm 自动分配 GPU 并启动 Triton 容器。#!/bin/bash #SBATCH --partitioninfer #SBATCH --gresgpu:1 #SBATCH --cpus-per-task8 #SBATCH --job-nametriton-infer #SBATCH --output/var/log/slurm/%x-%j.log #SBATCH --error/var/log/slurm/%x-%j.log export CUDA_VISIBLE_DEVICES${CUDA_VISIBLE_DEVICES:-0} docker run --rm \ --gpus device${CUDA_VISIBLE_DEVICES} \ --shm-size1g \ -p 8000:8000 \ -p 8001:8001 \ -p 8002:8002 \ -v /data/model_repository:/models \ nvcr.io/nvidia/tritonserver:version-py3 \ tritonserver --model-repository/models脚本中值得注意的地方#SBATCH --gresgpu:1声明这个作业需要 1 块 GPU$CUDA_VISIBLE_DEVICES是 Slurm 在分配 GPU 后自动注入的环境变量里面是当前作业可用的 GPU 编号列表Docker 参数--gpus device${CUDA_VISIBLE_DEVICES}把调度器分配的那张卡传给容器避免容器看到节点上的所有卡端口映射8000:8000用于 HTTP 推理8001用于 gRPC8002用于 Prometheus 指标。version替换成实际可用的镜像 tag 即可不同 Triton 版本对 CUDA 和驱动版本的要求不同以官方文档为准。5.3 提交作业并查看状态sbatch run_triton.sh squeuesqueue会显示作业状态。刚开始可能是PENDING等资源分配成功后变成RUNNING。如果一直PENDING可以用scontrol show job jobid查看等待原因最常见的是Resources说明没有空余资源也可能是PartitionConfig说明分区配置不正确。6. 运行验证与资源观测作业从PENDING变成RUNNING并不意味着推理服务已经就绪。Triton 启动需要加载模型这个过程通常需要几十秒到几分钟取决于模型大小。我们需要通过健康检查和推理请求来确认服务真正可用。6.1 检查服务健康状态Triton 提供 HTTP 健康检查接口curl -v http://localhost:8000/v2/health/ready返回 HTTP 200 表示服务已经就绪可以接收推理请求。如果返回 503说明模型仍在加载或部分模型加载失败。也可以查看作业日志tail -f /var/log/slurm/triton-infer-jobid.log日志中会出现模型加载记录。出现Successfully loaded model表示对应模型加载成功。6.2 发送一个推理请求接下来用 Python 客户端验证推理链路。以下代码使用 HTTP 接口向 Triton 请求一个模型推理结果import httpx payload { inputs: [ { name: input, shape: [1, 128], datatype: INT32, data: [[1] * 128] } ] } response httpx.post( http://localhost:8000/v2/models/text_encoder/infer, jsonpayload, timeout30, ) result response.json() print(result[outputs])如果输出中有output张量和对应的data说明整个链路已经跑通Slurm 分配 GPU、容器启动、模型加载、HTTP 推理请求全部正常。6.3 在节点上观察 GPU 使用情况在计算节点上执行nvidia-smi会看到 Triton 进程占用了分配的 GPU。更重要的是检查显存和利用率是否符合预期。如果在容器内看不到 GPU或者nvidia-smi报错问题通常出在容器运行时配置或者环境变量传递环节可以对照下一节的排查表处理。7. 常见问题与排查思路推理编排链路涉及的组件较多从 Slurm 到容器运行时再到推理框架每一层都可能出现问题。下面整理一份高频问题排查表。问题现象可能原因排查方式解决方案作业一直处于 PENDINGGPU 资源不足或分区配置不正确scontrol show job jobid查看 Reason扩容节点 GPU或修改slurm.conf中的分区和Gres配置作业已在 RUNNING但容器内nvidia-smi报错NVIDIA Container Toolkit 未安装或 Docker 未配置 runtime宿主机执行sudo nvidia-ctk runtime configure --runtimedocker重新测试容器重新配置并重启 Docker验证docker run --rm --gpus all nvidia/cuda:... nvidia-smi多卡节点上作业只用到一张卡脚本没有正确传递CUDA_VISIBLE_DEVICES查看作业日志中的环境变量输出在启动脚本中显式导出$CUDA_VISIBLE_DEVICES并传给 Docker 的--gpus参数Triton 启动成功但部分模型加载失败模型仓库目录结构或config.pbtxt配置错误查看 Triton 日志中对应的模型加载报错检查模型目录的版本号子目录和config.pbtxt字段推理请求返回 404 或 400请求的模型名、输入名或张量形状不匹配先访问/v2/models/model_name查看模型元数据按元数据修正请求中的name、shape和datatype节点被 Slurm 标记为 DRAINEDGPU 设备异常或 slurmd 探测失败scontrol show node nodename查看 Drain Reason在节点上执行nvidia-smi修复 GPU 驱动或硬件问题后执行scontrol update NodeNamenodename StateRESUME端口被占用导致容器启动失败多个推理作业被分配到同一节点且映射相同端口查看节点端口占用ss -lntp改进端口分配策略例如为每个作业分配独立端口段或通过配置中心动态分配容器启动后显存被其他任务挤占没有做显存隔离检查同节点其他容器的CUDA_VISIBLE_DEVICES收紧 GPU 资源隔离策略必要时为推理分区单独预留节点这些问题的共同特点是很多错误并不会在调度层暴露而是你等到服务真正启动后才发现环境不对。所以建议把“运行验证”作为标准化流程的一部分每次提交作业后自动执行一次健康检查而不是靠人工发现。8. 生产环境最佳实践从一个能跑的 Demo到一个稳定的推理平台中间还有不少工程化工作。下面是几条我认为最重要的实践建议。8.1 分区规划要面向业务场景不要把训练任务和在线推理任务混在同一个分区。推理服务通常要求资源能够立即获得不能排太久队而训练任务对排队不敏感但对算力规模要求高。建议把 GPU 节点分成若干分区例如train分区用于训练infer-online分区用于在线推理infer-batch分区用于离线批量推理。不同分区可以配置不同的MaxTime在线服务分区甚至可以不允许作业因资源不足而无限等待。同时可以给关键节点打上不同的特征标签通过Feature字段区分是否有 MIG、显存大小、GPU 型号等。这样在提交推理任务时可以直接声明需要什么规格的 GPU。8.2 GPU 隔离要落实到两层第一层是 Slurm 的资源分配通过--gresgpu:1确保两个作业不会被调度到同一张卡上。第二层是容器内环境依赖CUDA_VISIBLE_DEVICES和 NVIDIA Container Toolkit 让容器只“看得到”被分配的那张卡。需要注意默认的 Docker 容器在宿主机上只要具备--gpus all权限仍然可能通过 GPU 直通或其他方式访问同一张卡上的资源。如果你的推理场景对隔离要求极高需要结合 cgroup 的 GPU 设备控制甚至考虑 MIG 切分从硬件层面做隔离。8.3 模型仓库和镜像版本化推理服务的可重复性很大程度取决于模型和镜像是否可追溯。模型仓库建议使用对象存储或共享文件系统统一管理每个模型目录对应版本号镜像则建议在 CI 阶段打好确定的 tag部署时使用完整镜像地址避免使用latest。这样出现问题后可以快速回滚到上一个稳定版本。8.4 健康检查与自动拉起在线推理服务不能“挂了没人管”。在 srt-slurm 这类编排方案里可以考虑给每个推理作业配置一个心跳脚本定期请求/v2/health/ready如果连续失败则主动触发作业退出由上层系统重新提交作业。这比人工发现故障再处理要可靠得多。8.5 监控指标要统一采集NVIDIA 官方推理镜像通常自带 Prometheus 指标导出。Triton 默认在8002端口提供/metrics接口包括 GPU 利用率和推理请求延迟等关键指标。建议在集群中统一部署 Prometheus Grafana使用node-exporter采集节点指标使用 Triton 的 exporter 采集推理指标。这是判断“编排之后资源利用率是否真的提升”最重要的数据来源。8.6 安全与权限最小化生产环境中应避免直接使用 root 运行推理容器。Triton 镜像支持非 root 运行启动时通过--user参数指定用户并且模型仓库目录不要让所有开发人员都能写。Slurm 本身的权限模型也需要严格设置普通用户只允许向指定的分区提交作业不能随便修改节点配置。9. 总结与下一步推理部署正在从“一个人用一条命令跑通一个模型”走向“一个平台支撑多个团队、多类模型、多卡集群的统一调度”。NVIDIA 开源 srt-slurm 这类项目正是在这个大背景下出现的它不追求替代你熟悉的调度系统而是在 Slurm 的资源管理之上把推理服务变成可提交、可部署、可观测的标准化实体。如果你正在规划内部推理平台我建议不要一上来就追求大规模的调度优化。先把最小链路跑通准备一台带 GPU 的机器装好驱动和容器运行时配置 Slurm 识别 GPU写一个脚本提交 Triton 服务用 Python 客户端发一次推理请求。等到这条链路顺畅之后再逐步增加分区规划、MIG 切分、监控告警和多节点调度。这个阶段会把大部分环境问题暴露出来而它们恰恰是后续所有工作能稳定的基础。最终你会发现在推理编排里真正的技术难点不是某个单点能力有多强而是从“资源”到“服务”的过程是否足够流畅、可重复、可观察。想清楚这一点再去看 srt-slurm 或其他调度方案你的判断会比单看功能介绍准确得多。
返回列表