4、作业提交:sbatch命令详解、srun交互式作业、作业脚本编写规范
好,咱们进入正题。作业提交这块,是大家每天都要打交道的。说白了,你写好的并行程序,怎么交给集群去跑?就靠这俩命令:sbatch 和 srun。我见过不少新手,上来就 srun ./a.out,结果把登录节点搞崩了……嗯,咱们今天就把这事彻底捋清楚。
4.1 sbatch:批量作业提交的“正规军”
sbatch 是我个人最常用的命令。它会把你的作业脚本提交到调度队列里,然后后台排队、分配资源、执行。整个过程你不需要盯着,适合跑那种跑几小时甚至几天的任务。
基本用法很简单:
sbatch my_job.sh
但这里有个坑——脚本里必须写清楚你要多少资源。我曾经遇到一个用户,脚本里啥资源参数都没写,结果默认只给了一个CPU核心,他的MPI程序跑了三天还没跑完……
所以,我建议你在脚本头部加上这些参数:
#!/bin/bash
#SBATCH -J my_test_job # 作业名称
#SBATCH -N 2 # 申请2个节点
#SBATCH -n 32 # 总共32个任务(进程)
#SBATCH --cpus-per-task=1 # 每个任务1个CPU核心
#SBATCH --mem=64G # 每个节点内存64GB
#SBATCH -t 02:00:00 # 运行时间上限2小时
#SBATCH -p normal # 分区(队列)名称
#SBATCH -o %j.out # 标准输出文件
#SBATCH -e %j.err # 标准错误文件
# 加载环境
module load intel/2021.4.0
module load openmpi/4.1.2
# 运行程序
mpirun ./my_mpi_app
这里 %j 会被自动替换成作业ID。我个人习惯把输出和错误分开,方便排查问题。
4.2 srun:交互式作业的“快刀手”
srun 是另一种提交方式。它直接在前台运行,你盯着终端看输出。适合调试代码、跑短任务、或者需要实时交互的场景。
比如你想快速测试一下MPI程序能不能跑通:
srun -N 2 -n 16 --pty bash
这条命令会给你分配两个节点、16个核心,然后弹出一个交互式shell。你可以在里面编译、调试、跑程序。跑完了 exit 退出,资源自动释放。
为什么会用 --pty?说白了,就是分配一个伪终端,让你能像在本地一样操作。我刚开始用的时候没加这个参数,结果连 ls 命令都执行不了……
另一个常用场景是直接跑程序:
srun -N 4 -n 64 ./my_mpi_app
注意,srun 默认会从当前终端继承环境变量。所以你在 sbatch 脚本里需要 module load,但 srun 交互式环境下,你提前加载好就行。
ls 都卡。我曾经见过有人直接在登录节点跑深度学习训练,结果整个集群的登录服务都挂了……
4.3 作业脚本编写规范:别让调度器“看不懂”
作业脚本,说白了就是一个带特殊注释的Shell脚本。调度器通过 #SBATCH 开头的注释来解析你的需求。这里有几个规范,是我多年运维经验总结的:
4.3.1 脚本头部必须清晰
我建议每个脚本都包含以下信息:
- 作业名称:别用默认的
job,改成有意义的,比如weather_model_v2。 - 资源需求:节点数、核心数、内存、时间,一个都不能少。
- 分区选择:不同分区可能有不同限制,比如GPU分区、大内存分区。
- 输出重定向:把标准输出和错误分开,方便定位问题。
4.3.2 环境加载要放在前面
我见过不少脚本,把 module load 写在程序运行命令后面……那肯定加载不上啊。正确的顺序是:先加载环境,再运行程序。
# 正确做法
module purge
module load intel/2021.4.0
module load openmpi/4.1.2
# 再运行
mpirun ./app
4.3.3 善用变量和参数
别把路径写死。我习惯用变量:
#!/bin/bash
#SBATCH -J my_job
#SBATCH -N 2
#SBATCH -n 32
INPUT_DIR="/data/input"
OUTPUT_DIR="/data/output/${SLURM_JOB_ID}"
APP_DIR="/home/user/app"
mkdir -p ${OUTPUT_DIR}
cd ${APP_DIR}
mpirun ./simulation -i ${INPUT_DIR}/case1.dat -o ${OUTPUT_DIR}/result.dat
这样每次提交不同任务时,只需要改变量值,不用改整个脚本。
4.3.4 错误处理不能少
我曾经遇到一个脚本,程序跑崩了,但脚本继续往下执行,把错误结果当成正确结果传给了下一个任务……所以,我建议加上简单的错误检查:
mpirun ./app
if [ $? -ne 0 ]; then
echo "Error: application failed"
exit 1
fi
4.4 实战对比:sbatch vs srun
| 特性 | sbatch | srun |
|---|---|---|
| 运行方式 | 后台排队,非交互 | 前台运行,交互式 |
| 适用场景 | 长时间、批量任务 | 调试、短任务、交互 |
| 资源释放 | 脚本执行完自动释放 | 退出终端或程序结束释放 |
| 环境继承 | 脚本内需手动加载 | 继承当前终端环境 |
| 典型用法 | sbatch job.sh |
srun -N 2 ./app |
sbatch,调试环境用 srun。别搞反了,否则要么浪费资源,要么耽误时间。
嗯,作业提交这块,说白了就是让调度器听懂你的需求。你给它说清楚要多少资源、跑什么程序、输出放哪里,它就能帮你安排得明明白白。我见过太多因为脚本不规范导致的“惨案”——资源申请太多被管理员警告,申请太少程序跑崩,输出没重定向找半天日志……
所以,养成好习惯,从写好一个 sbatch 脚本开始。