Slurm GPU 集群作业提交、资源申请与调度排错。
Slurm 是 HPC 和训练集群常用的作业调度器。GPU 训练的关键是正确声明 GRES、CPU、内存和时限,并理解 cgroup 约束与排队原因。
本文以单机多卡和单节点多作业为主,集群管理命令需要相应权限。
sinfo -o "%20P %5D %14F %8z %10m %25N %10G"
scontrol show node "$NODE" | grep -Ei 'state|gres|cpu|real_memory'
scontrol show config | grep -Ei 'SelectType|GresTypes'
节点没有注册 GPU 时,先检查 gres.conf 的 AutoDetect=nvml 和 slurm.conf 的 GresTypes=gpu。
提交单机 8 卡训练作业:
cat > train.sbatch <<'SH'
#!/bin/bash
#SBATCH --job-name=qwen-sft
#SBATCH --partition=gpu
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=64
#SBATCH --gres=gpu:8
#SBATCH --mem=512G
#SBATCH --time=24:00:00
#SBATCH --output=%x-%j.out
set -euo pipefail
export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK
torchrun --nproc_per_node=8 train.py --config config.yaml
SH
sbatch train.sbatch
squeue -u "$USER" -o "%.18i %.9P %.30j %.8T %.10M %.6D %R"
交互式申请一张卡调试:
salloc --partition=gpu --nodes=1 --ntasks=1 --cpus-per-task=16 \
--gres=gpu:1 --mem=64G --time=2:00:00
srun --pty bash
nvidia-smi
exit
作业结束后核对资源与退出状态:
sacct -j "$JOBID" --format=JobID,JobName,Partition,Elapsed,State,ExitCode,MaxRSS,AllocTRES%50
维护节点:
scontrol update NodeName="$NODE" State=DRAIN Reason="GPU ECC error"
scontrol update NodeName="$NODE" State=RESUME
slurm.conf 没有 GresTypes=gpu 时,--gres=gpu:1 直接报错;配置改动需要重启 slurmctld 和节点。--gpus、--gpus-per-node 在旧版或未启用相关配置的集群不可用;可移植写法是 --gres=gpu:N。--gres=gpu:a100:8,前提是 gres.conf 里定义了对应 Type,否则会报无可用资源。--mem 和 --mem-per-cpu 同时写会提交失败;二选一,并给数据加载留出余量。CUDA_VISIBLE_DEVICES 为空,训练脚本会退回 CPU;检查分配环境变量。srun 启动并开启 cgroup。OUT_OF_MEMORY;sacct 的 MaxRSS 可定位峰值。TIMEOUT;训练要定期 checkpoint,并留出保存时间。ReqNodeNotAvail 常见于节点被 DRAIN、预留或请求时限超过分区上限;用 scontrol show job 看原因。srun 的 --ntasks 大于 1 又叠加 torchrun 会启动重复进程;单机多卡用 ntasks-per-node=1 加 torchrun。--gres=gpu:1g.10gb:1 写法,直接复用整卡配额会失败。合上页面,先回答,再展开对照。
torchrun --nproc_per_node=8 而不是 8 个 srun 任务?--mem 和 --mem-per-cpu 怎么选?srun 进入分配、cgroup 未约束,或集群没配置 GPU GRES。先在分配内运行 nvidia-smi -L 和 env | grep CUDA 确认。srun --ntasks=8 会变成 64 个进程,争抢同一批 GPU。--mem 是作业总内存,--mem-per-cpu 会乘以申请的核心数;后者在核心多时容易申请过量。