Slurm在作业运行过程中释放部分节点,使它们成为该作业内部的子作业/任务,直到作业结束

编程语言 2026-07-11

我有很多任务要执行。我可以独立提交每个任务,但我所用集群的排队系统会优先处理较大的作业,因此大任务常常需要等待数月。

相反,我开始提交更大的作业,其中每个作业随后会启动若干子作业或任务,以并行方式运行。

这都运行得很好。然而,各个任务完成所需的时间差异可能很大,通常在4到16小时之间,而且我没有一个好办法能够事先判断每个任务需要多久。

这意味着大量节点会空闲数小时,数据设施的管理层对此并不感到高兴。

我想做的是在每个任务完成后释放它所运行的节点。我尝试使用 scontrol update 在任务运行时更新作业,但没有成功。

当前用于启动作业的脚本大致如下:

#!/bin/bash
#SBATCH -J thisJobName
#SBATCH --nodes=40
#SBATCH --ntasks-per-node=128
#SBATCH -t 24:00:00
#SBATCH --mem=0

source /path/to/load_modules

srun --nodes=5 --exclusive --ntasks-per-node=128 Task0 &
srun --nodes=5 --exclusive --ntasks-per-node=128 Task1 &
srun --nodes=5 --exclusive --ntasks-per-node=128 Task2 &
srun --nodes=5 --exclusive --ntasks-per-node=128 Task3 &
srun --nodes=5 --exclusive --ntasks-per-node=128 Task4 &
srun --nodes=5 --exclusive --ntasks-per-node=128 Task5 &
srun --nodes=5 --exclusive --ntasks-per-node=128 Task6 &
srun --nodes=5 --exclusive --ntasks-per-node=128 Task7 &

wait

我尝试在任务完成后释放节点的方法大致如下:

while true; do
    nodesToKeep=""
    anyFinishedTasks=false
    anyRunningTasks=false
    # Check if any tasks have finished. Keep track of the nodes still in use
    for task in $(seq 0 7); do 
        """Check if task is completed"""
        if [ """task is not completed""" ]; then
            # Find nodes this task is running on
            taskNodes=$(sacct -n -j ${SLURM_JOB_ID}.${task} -o 'Nodelist%100')
            # Remove spaces from output
            taskNodes=${taskNodes//" "/""}
            nodesToKeep="${nodesToKeep}${taskNodes},"
            anyRunningTasks=true
        else
            anyFinishedTasks=true
        fi
    done

    # if no tasks are still running, break out of the loop
    if [ $anyRunningTasks = false ]; then
        break
    fi 


    ### -------------------------------------------
    ### THIS IS THE IMPORTANT PART THAT DOESNT WORK
    ### -------------------------------------------
    # If any tasks have finished, Update the node list for the job to not include the ones no longer in use
    if [ $anyFinishedTasks = true ]; then
        scontrol update jobid=${SLURM_JOB_ID} NodeList=$nodesToKeep
        . ./slurm_job_${SLURM_JOB_ID}_resize.sh
    fi    
    ### ------------------------------------------
    ### END OF THE IMPORTANT PART THAT DOESNT WORK
    ### ------------------------------------------


    # Check again in 5 more minutes
    sleep 300
done
wait

然而,这会给我一个错误信息,说是

Invalid node name specified for job 1016205

Trying to run a test where i allocate an extra node which never gets assigned to a task, I have found that the extra node can be deallocated in this way, so the error is not in the way i am listing the nodes.

如果不使用 scontrol update jobid=${SLURM_JOB_ID} NodeList=$nodesToKeep 而改用 scontrol update jobid=${SLURM_JOB_ID} NumNodes=${numberOfNodesToKeep}(其中 numberOfNodesToKeep 只是40-5*[number of finished tasks]),我会得到以下错误消息

Job is no longer pending execution for job 1016205

对一个问题的另一个回答这里建议 scontrol update jobid=${SLURM_JOB_ID} NumNodes=${numberOfNodesToKeep}-${numberOfJobsToKeep} 能工作,但结果仍然一样。

我不知道为什么这些选项都不起作用,我已经快想不出主意了。

编辑:已解决 我找到了问题。一台节点被分配为从中运行脚本的“批处理节点”。该节点不能被回收。因此,用 sacct -j ${SLURM_JOB_ID}.batch -o 'NodeList' 找出该节点,并确保该节点始终保留在要保留的节点列表中,这样一切就能顺利工作。批处理节点因此保持分配,即使在该节点上运行的任务完成,但只有一个单独的节点在大多数时间处于空闲状态,远比有20个空闲节点要好。希望如果有人在某个时候遇到同样的问题,这能有所帮助。

解决方案

我找到了问题。一台节点被分配为从中运行脚本的“批处理节点”。这台节点不能被回收。因此,用 sacct -j ${SLURM_JOB_ID}.batch -o 'NodeList' 找出该节点,并确保该节点始终保留在要保留的节点列表中,这样一切就能顺利工作。批处理节点因此保持分配,即使在该节点上运行的任务完成,但只有一个单独的节点在大多数时间处于空闲状态,远比有20个空闲节点要好。希望如果有人在某个时间遇到同样的问题,这能有所帮助。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章