Slurm 运行中的作业如何在任务结束后释放部分节点?
可以释放已完成任务所使用的部分节点。在给出的环境中,缩容失败的关键原因是待保留的 NodeList 遗漏了运行批处理脚本的 batch node。将这个节点和所有仍在运行的任务所用节点一起保留后,scontrol update ... NodeList=... 就能正常完成缩容。
这个结论适用于题目中已经验证的环境,不能据此保证所有 Slurm 版本和集群配置都允许以相同方式调整运行中的作业。
为什么任务结束了,节点仍不能直接释放?
脚本先通过 sbatch 申请 40 个节点,再通过多个 srun 启动作业步骤,也就是 job steps。某个 srun 结束,只表示对应步骤完成,整个作业的节点不一定已经归还。
批处理脚本本身也需要运行位置,也就是 .batch 步骤所在的 batch node。即使该节点上负责计算的 TaskN 已经完成,主脚本仍可能在这里执行监控循环和 wait。
因此,待保留的节点集合应为:
仍在运行的作业步骤所用节点 ∪ batch node
原来的循环只收集未完成任务的节点。batch node 上的计算任务结束后,这个节点就可能被排除,导致节点更新失败。
如何修改节点释放逻辑?
先查询 batch node:
sacct -j "${SLURM_JOB_ID}.batch" -o 'NodeList'
确认查询结果后,在每次执行节点更新前,将它加入 nodesToKeep。下面的片段用于替换原循环中的更新部分;前提是已有逻辑已经正确收集所有仍在运行的任务节点,并设置了 anyFinishedTasks。
if [ "$anyFinishedTasks" = true ]; then
batchNode=$(sacct -n -j "${SLURM_JOB_ID}.batch" -o 'NodeList%100')
batchNode=${batchNode//[[:space:]]/}
if [ -z "$batchNode" ]; then
printf 'Cannot determine batch node; skipping resize.\n' >&2
else
# Remove the trailing separator left by the collection loop.
nodesToKeep=${nodesToKeep%,}
# Always retain the node running the batch script.
nodesToKeep="${nodesToKeep:+${nodesToKeep},}${batchNode}"
scontrol update \
jobid="${SLURM_JOB_ID}" \
NodeList="$nodesToKeep"
fi
fi
这段代码保留了原脚本使用的 NodeList%100 输出宽度。使用前需要确认节点名称或节点表达式没有被截断;如果输出不完整,应调整查询格式后再执行更新。整理节点集合时也应去除重复节点。
如果原环境还需要加载 slurm_job_${SLURM_JOB_ID}_resize.sh,应在节点更新成功且脚本确实存在时执行。它不能代替保留 batch node 的逻辑。
为什么改用 NumNodes 仍然报错?
NumNodes 只表达希望保留的节点数量,无法指定哪些节点必须留下。即使算出了 40-5*[已完成任务数],也无法确保保留 batch node 和运行中步骤所用的节点。
下面的报错与作业状态及该环境接受的更新方式有关:
Job is no longer pending execution for job 1016205
现有信息没有包含 Slurm 版本、集群配置或更完整的诊断结果,无法进一步确定 NumNodes 在该环境中的具体限制。把整数改成范围也没有解决已观察到的问题。在这个案例中,已有验证支持显式更新 NodeList,并始终包含 batch node。
执行缩容前还要检查什么?
- 确认步骤确实结束。原循环中的三引号内容只是占位表达,不能直接用作 Bash 的任务状态检查逻辑。
- 确认步骤 ID。
Task0等程序名称并不保证对应.0等步骤编号,应以实际启动得到的 job step ID 为准。 - 保留全部运行中步骤的节点。查询不到节点、输出为空或状态尚未确认时,应跳过此次缩容,避免提交不完整的列表。
- 检查更新结果。
scontrol update失败后,应记录报错并保留当前分配,不要继续按缩容成功处理。
所有计算任务结束后,让监控循环退出,再由批处理脚本正常结束。仍被保留的 batch node 会随整个作业结束而归还,无需在脚本运行期间强行释放。
备注:内容仅供参考。
