第1章 作业调度系统入门:SLURM基础概念、作业提交与监控、作业脚本编写规范
1.1 为什么我们需要作业调度系统?
说实话,我刚入行那会儿,也觉得调度系统挺烦人的。
明明我有代码,有数据,直接跑不就完了?干嘛还要学一套新工具?
后来我接手了一个集群,有32个节点,每个节点64核。好家伙,大家一窝蜂往上提交任务,结果呢?
- 有人占了全部内存,别人跑不了
- 有人开了100个进程,把CPU打满了
- 还有人跑着跑着断连了,作业直接丢了
嗯,这时候我才明白——没有调度系统的集群,就是菜市场。
SLURM就是那个「管理员」。它帮你排队、分配资源、监控状态。说白了,它是高通量计算的基石。
核心认知:SLURM不是用来限制你的,而是用来保护你的。保护你的作业不被别人干扰,也保护别人不被你干扰。
1.2 SLURM的三大核心组件
我习惯把SLURM理解成一个「三驾马车」的结构。你想想看,一个调度系统要干三件事:
- 知道集群有什么资源 —— 谁在干活?谁闲着?
- 决定谁先跑 —— 排队、优先级、抢占
- 执行任务 —— 把作业发到计算节点上
对应到SLURM里,就是三个角色:
| 组件 | 角色 | 我常说的比喻 |
|---|---|---|
| slurmctld | 中央控制器 | 「大管家」—— 管排队、管分配 |
| slurmd | 计算节点守护进程 | 「分店店长」—— 听大管家指挥,干活 |
| sacctmgr / sacct | 账户与记账工具 | 「财务」—— 谁用了多少资源,记下来 |
我在项目中遇到过一个问题:slurmctld挂了,所有作业都卡住了。为什么?因为「大管家」不在,没人知道下一步该干啥。所以生产环境一定要做高可用部署,这个后面会讲。
1.3 作业提交:从零开始跑第一个任务
好,理论说完了,咱们直接上手。
你只需要一个命令:sbatch。
先写一个最简单的作业脚本,我叫它 hello.slurm:
#!/bin/bash
#SBATCH --job-name=my_first_job
#SBATCH --output=output_%j.txt
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=2
#SBATCH --mem=4G
#SBATCH --time=00:05:00
echo "Hello, SLURM!"
echo "当前节点是: $(hostname)"
sleep 30
echo "任务完成!"
然后提交:
sbatch hello.slurm
你会看到类似这样的输出:
Submitted batch job 12345
这个 12345 就是作业ID。记住它,后面监控、取消都要用它。
我的小习惯:作业脚本文件名我一般用 .slurm 后缀,方便区分。也有人用 .sh,都可以。但千万别用 .job —— 我见过有人用这个,结果被系统误判成别的格式,坑了自己。
1.4 作业监控:看看你的任务跑得怎么样了
提交完作业,你肯定想知道它跑没跑、跑在哪、跑多久了。
三个命令,记住就行:
squeue—— 查看队列状态sacct—— 查看历史作业scancel—— 取消作业
咱们一个个说。
squeue:实时队列
squeue -u 你的用户名
输出大概长这样:
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
12345 normal my_first_job zhang R 0:32 1 node01
12346 gpu gpu_job li PD 0:00 1 (Resources)
注意看 ST 这一列:
R= Running,正在跑PD= Pending,排队中CG= Completing,即将完成
我曾经遇到一个情况:作业一直PD,我以为是系统卡了。后来一查,是我申请了128G内存,但集群最大节点只有64G。嗯,这作业永远跑不了。所以资源申请要合理。
sacct:历史记录
sacct -j 12345 --format=JobID,JobName,State,Elapsed,MaxRSS
这个命令特别有用。它能告诉你作业到底用了多少内存、跑了多久、有没有失败。
避坑指南:我曾经用 sacct 查一个作业,发现它显示 FAILED,但输出文件里全是正常日志。为什么?因为作业最后一步报错了,但前面的都成功了。所以一定要看 State 列,别只看输出文件。
scancel:取消作业
scancel 12345
就这么简单。如果你想取消所有自己的作业:
scancel -u 你的用户名
但小心,别手滑。我有个同事曾经在调试的时候,一个 scancel -u root 把全集群的作业都干掉了……嗯,那天他请全组喝了奶茶。
1.5 作业脚本编写规范:别让你的脚本变成「地雷」
写SLURM脚本,说白了就是写一个带「头信息」的bash脚本。但这个头信息,很多人写不好。
我总结了三条铁律:
- #SBATCH 必须写在脚本最前面,而且不能有空格
- 资源申请要精确,别多申请,也别少申请
- 输出路径要明确,别让日志散落一地
来看一个规范的例子:
#!/bin/bash
#SBATCH --job-name=my_job
#SBATCH --output=/home/zhang/logs/%x_%j.out
#SBATCH --error=/home/zhang/logs/%x_%j.err
#SBATCH --partition=normal
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=8
#SBATCH --cpus-per-task=1
#SBATCH --mem=16G
#SBATCH --time=02:00:00
# 加载环境
module load python/3.9
# 进入工作目录
cd /home/zhang/project
# 运行任务
python run.py --input data.txt --output result.txt
注意几个细节:
%x会被替换成作业名,%j替换成作业ID。这样日志文件不会重名。--time一定要写。不写的话,默认可能是无限时长,调度器会很难分配。--partition指定分区。不同分区可能有不同硬件,比如GPU分区、大内存分区。
我的经验:我见过最离谱的脚本,申请了 --mem=999999G。结果作业永远排不上队。你想想看,哪个节点有999T内存?所以资源申请要合理,先查一下集群配置:sinfo -o "%n %m %c" 可以看每个节点的内存和CPU。
1.6 本章知识体系总览
下面这张图,是我自己梳理的SLURM入门知识结构。你看一眼,心里就有谱了。
1.7 本章小结
这一章,咱们把SLURM的底子打好了。
- 知道了SLURM是干什么的——说白了就是集群的「交通警察」
- 理解了三大组件——大管家、店长、财务
- 亲手提交了第一个作业——
sbatch没那么可怕 - 学会了监控——
squeue、sacct、scancel三件套 - 掌握了脚本规范——头信息、资源申请、输出路径
我个人觉得,学SLURM最忌讳的就是「眼高手低」。你光看文档不实操,永远记不住。我建议你现在就去集群上跑一个作业试试,哪怕只是打印一句 Hello。跑通了,你就入门了。
课后小练习:写一个SLURM脚本,申请4个CPU、8G内存,运行 sleep 60,然后用 squeue 观察它的状态变化。试试看能不能在它运行的时候用 scancel 取消它。
公众号:蓝海资料掘金营,微信deep3321