Slurm 学习路径:从装起来到能提交作业
先说这张页面是什么:不是「Slurm 是什么」的科普,也不是又一篇安装教程。它是一张路标——把站内已经写好的五篇 Slurm 文章按实际动手顺序排成一条路,每一站给出目标、读哪篇、敲什么命令、怎么算通过。
如果你现在只想提交作业、不想碰集群,直接跳到 第三站。
三条起点,别从同一页开始
| 你的处境 | 从哪进 | 为什么 |
|---|---|---|
| 手上有一批裸机,要搭一套能用的 Slurm | 第一站 | 部署两篇(Rocky / Ubuntu)任选其一,按发行版走 |
| 集群已经有人搭好,你只是新接手 | 第二站 | 先学会「怎么看」再去改,别一上来动 slurm.conf |
| 只要会提交和管理作业 | 第三站 | 前面两站对你是噪音 |
第一站:把控制面和计算面拉起来
目标:slurmctld 与 slurmd 都处于 active,sinfo 能看到节点,节点不是 down。
读哪篇:按发行版二选一——Rocky Linux 9 全流程 或 Ubuntu 22.04 + Slurm 24.05。两篇的骨架一致,差别在包管理与 systemd 单元命名。
动作(顺序不要换,换了几何级增加排错成本):
- 先定主机名与解析,
slurm.conf里的SlurmctldHost必须是hostname -s能解释的名字; - 统一 munge:所有节点同一把
/etc/munge/munge.key,属主munge、权限400。这是 Slurm 唯一的手工「信任根」,密钥不一致的表现是节点永远down而日志只说认证失败; - 用
slurmd -C生成节点行,而不是手抄 CPU/内存参数——它直接读本机实际值,能避免RealMemory写小导致作业被降级; - 再起服务,最后才动
slurm.conf里的调度策略。
验收:
systemctl status slurmctld slurmd --no-pager | grep -E "Active|slurm"
sinfo -N -l # 每行一个节点,STATE 不能是 down/inval
scontrol show node node01 | grep -E "State|RealMemory|CfgTRES|Gres"卡点:sinfo 里节点 down*,星号意思是「有人手动设的」。先看 sinfo -R 给出的原因,处理完再 scontrol update NodeName=node01 State=RESUME。没处理根因直接 RESUME,下一次心跳还会 down。
第二站:让节点真正可用(接手集群必读)
目标:节点 idle、GPU 能被识别为可分配资源、作业不会因为内存被系统杀掉。
读哪篇:Slurm 作业提交与管理指南 的前半部分,讲清了 sinfo/scontrol/squeue 的判读;配置侧看部署篇的 slurm.conf 章节。
必查的四件事:
| 检查点 | 命令 | 期望 |
|---|---|---|
| GPU 是否被登记为 GRES | scontrol show node node01 | grep Gres | 有 gpu:... 计数,不是空 |
| 可分配 CPU/内存 | sinfo -N -o "%N %c %m %e" | %c 与实际核数一致 |
| cgroup 是否生效 | scontrol show config | grep -E "ProctrackType|TaskPlugin" | proctrack/cgroup + task/cgroup |
| 计费是否落库 | sacct -a -n | head | 有记录;空则 slurmdbd 未接 |
关键参数(这六个改错会直接影响能不能用,其余保持默认即可):
SelectType=select/cons_tres
SelectTypeParameters=CR_Core_Memory # 允许按核+内存组合分配
GresTypes=gpu
ProctrackType=proctrack/cgroup
TaskPlugin=task/cgroup
DefMemPerCPU=4000 # 按核给默认内存,避免 --mem 不写就无限制SelectType 用 cons_tres(消费型可追踪资源)而不是老的 cons_res,是能否按「核 + 内存 + GRES」精细分配的前提。
第三站:提交第一个作业
目标:能用 srun 交互跑一条命令,能用 sbatch 跑一个脚本,能用 squeue/scontrol 看出它在干什么。
读哪篇:Slurm 作业提交与管理指南。
最小可用序列:
# 1) 一条命令的冒烟测试:2 节点 × 8 任务 × 每节点 1 卡
srun -N2 --ntasks-per-node=8 --gres=gpu:1 hostname
# 2) 语法检查,不真正排队(省掉「排了两小时才发现脚本有错」)
sbatch --test-only job.sbatch
# 3) 提交并盯住
sbatch job.sbatch
squeue -u "$USER" -o "%.10i %.20j %.10P %.2t %.10M %R"一个能直接用的 job.sbatch 骨架:
#!/bin/bash
#SBATCH -J train-demo
#SBATCH -p gpu
#SBATCH -N 2
#SBATCH --ntasks-per-node=8
#SBATCH --gres=gpu:1
#SBATCH --cpus-per-task=4
#SBATCH --mem=64G
#SBATCH -t 02:00:00
#SBATCH -o logs/%j.out
#SBATCH -e logs/%j.err
set -euo pipefail
module load cuda/12.4
srun python -u train.py --epochs 10验收:作业从 PD 进到 R 再到 CD,sacct 能查到 Elapsed/ExitCode/MaxRSS。
sacct -j <jobid> --format=JobID,JobName,Partition,Elapsed,State,ExitCode,MaxRSS卡点:作业一直 PD 而不 R,八成不是排队,而是资源请求超过了单节点实际值(--mem 写 128G 但节点只有 120G,或者 --gres=gpu:2 但节点只登记了 1 卡)。此时 scontrol show job <id> 的 Reason 字段会直接告诉你原因。
第四站:把作业跑「对」而不只是跑「起来」
目标:多节点任务分布符合预期、CPU 亲和性不乱跳、MPI 混合并行不空转。
读哪篇:Slurm + Docker 分布式训练提交模板 讲容器场景;MPI 部分见 MPI + Slurm 实战:作业调度与性能调优;同机多卡的通信上限见 集合通信原语与库。
三个高频错法:
| 症状 | 根因 | 修正 |
|---|---|---|
| 开了 16 个任务,但只有一个进程在算 | 进程数由 --ntasks 决定,不是由 python 循环决定 | srun --ntasks=16,或用 --ntasks-per-node |
| MPI 程序卡在启动阶段 | mpirun 在 srun 里再套一层,任务重复展开 | 二选一:Slurm 下用 srun ./app,或 mpirun 配 --bootstrap 系列参数 |
| 性能只有一半 | 进程/线程在 NUMA 上漂移 | --cpu-bind=cores、OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK |
一个稳定的混合并行写法(每节点 2 个 MPI 进程 × 每进程 8 线程,绑核):
srun --ntasks-per-node=2 --cpus-per-task=8 --cpu-bind=cores \
bash -c 'export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK; ./solver'验收:srun hostname | sort | uniq -c 的任务分布与请求一致;sacct 里 MaxRSS 不超过申请值;sstat -j <id> -a 能看到每个任务的实时 CPU 效率。
第五站:让环境可复现(容器化)
目标:同一个镜像在任意节点上跑出同一结果,且不需要 root。
读哪篇:HPC 集群容器化:Apptainer 的 SIF、GPU 注入与 Slurm 落地;需要 Docker 而不是 Apptainer 的场景看 基于 Docker 的分布式训练提交模板。
要点:容器在 Slurm 里只是「srun 后面那个命令」——srun apptainer exec --nv x.sif python train.py。真正要决策的是三件事:镜像放哪(别让 200 个节点同时拉同一份)、挂载哪些目录(--containall 会清掉默认绑定)、GPU 驱动代际是否与宿主一致。
验收:srun apptainer exec --nv x.sif nvidia-smi 在分配到的每张卡上都能出表,且卡号与 CUDA_VISIBLE_DEVICES 一致。
六、一次性通过的验收清单
按顺序打勾,全部通过再对外说「集群可用」:
- [ ]
sinfo -N -l:所有节点idle/mixed,无down、无inval - [ ]
scontrol show node <n> | grep Gres:GPU 计数与实际一致 - [ ]
srun -N1 --ntasks=1 hostname:单节点冒烟通过 - [ ]
srun -N2 --ntasks-per-node=8 hostname:跨节点通过,任务数对得上 - [ ]
sbatch --test-only job.sbatch:语法与资源请求合法 - [ ] 真实作业跑完,
sacct有Elapsed/ExitCode/MaxRSS - [ ] 故意
scancel一次,确认作业能被干净回收,不残留CG态 - [ ] (可选)
slurmdbd接上,share/sshare能看到账户权重 - [ ] (可选)
srun apptainer exec --nv x.sif nvidia-smi通过
七、卡点速查
| 现象 | 先看这里 | 一句话处置 |
|---|---|---|
节点 down,日志报认证失败 | munge 密钥与权限 | 全节点同一把 key,属主 munge、400 |
sinfo 全 down* | 有人手动设过状态 | 根因处理完再 scontrol update ... State=RESUME |
作业长期 PD | scontrol show job 的 Reason | 多半是资源请求超过节点实际配置 |
作业瞬间 FAILED,ExitCode 非零 | %j.err | set -euo pipefail 让第一个错误就停 |
MaxRSS 超申请值 | cgroup 未生效 | ProctrackType/TaskPlugin 换成 cgroup 版 |
GPU 分到了但 nvidia-smi 报错 | 驱动/容器代际 | 容器内库版本要与宿主同代 |
slurmctld 起来又退 | slurmctld -Dvvv 前台跑一次 | 配置解析错会直接打在第一屏 |
收口三句
- 顺序比技巧重要:主机名与密钥 →
slurmd -C生成节点行 → 起服务 → 再调策略,这个顺序错了,后面每一步都在给前面擦屁股; sinfo/scontrol是你的仪表盘:任何「作业不跑」的问题,答案几乎都在Reason、State、Gres这三个字段里;- 能验收才算搭完:
srun冒烟、sbatch --test-only、sacct三件套跑通,比写满一页slurm.conf更有意义。
延伸阅读
- Rocky Linux 9 HPC 集群部署全流程
- Ubuntu 22.04 + Slurm 24.05 集群部署实战
- Slurm 作业提交与管理指南
- Slurm 实战:基于 Docker 的分布式训练提交模板
- HPC 集群容器化:Apptainer 的 SIF、GPU 注入与 Slurm 落地
- 集合通信原语与库:从 MPI 到 NCCL