每个节点最多有一个并发作业的 Slurm 数组作业

Slurm array job with at most one concurrent job per node

问题

我有数百个文件,对于每个文件,我都想 运行 一个具有固定内核数的作业(比方说 -c4),这样在任何时候都不会超过其中一个任何节点上的作业 运行。

(如果您感兴趣,原因:我无法控制复杂的作业设置。每个作业都会在硬编码端口上启动一堆服务器。如果 运行 同时在一个节点上发生冲突:-/(是的,别告诉我,我知道。))

MVCE

我已经尝试过 -N1-n1--ntasks-per-node=1 和内部 srun--exclusive 的各种组合,但是遗憾的是没有成功:

sbatch -N1 -n1 -c4 --ntasks-per-node=1 --array=1-128 --wrap \
    'echo "$(hostname) $(date) $(sleep 15) $(date)"'

sbatch -N1 -n1 -c4 --ntasks-per-node=1 --array=1-128 --wrap \
    'srun --exclusive -n1 -c4 --ntasks-per-node=1 -- \
         bash -c '\''echo "$(hostname) $(date) $(sleep 15) $(date)"'\'

但是,如果您查看输出 (cat slurm-*.out),您会在所有情况下快速发现重叠 运行s :-/

问题

有没有办法限制数组作业永远不会在任何节点上并发 运行 超过 1 个作业?

我们的集群非常异构。每个节点中的 CPU(范围从 32 - 256),如此简单的解决方法,例如要求足够高的 -c 以便节点上没有 2 个可以 运行 导致非常长的等待时间和低利用率.

有什么想法/建议吗? 有没有办法为每个作业保留某个端口?

我可以想到两种方法来实现这一点,一种需要一些管理员帮助,另一种不需要。:

  1. 如果您非常友好地询问您的 Slurm 管理员,他可能会向节点添加 'fake' gres。这允许您为您的工作请求此 gres。如果每个节点只有一个这样的 gres,那么每个节点应该限制为一个作业,但是您需要许多其他资源。
  2. 您可以请求一个有很多节点的大作业,但每个节点一个任务,每个节点四个核心,而不是使用数组。在该作业中,您使用 s运行 开始任务,并且由于每个节点都有一个任务,因此它们应该沿着节点分布。您可能不想等待 128 个节点上的四个核心同时空闲,因此将您的工作负载分成块并将它们提交为 dependencies(查看单例选项)。

第二个选项的详细说明:

#SBATCH -N16
#SBATCH --ntasks-per-node=1
#SBATCH --job-name=something
#SBATCH --dependency=singleton

for i in `seq 1 $SLURM_JOB_NUM_NODES`; do
  srun -N1 -n1 <your_program> &
done
wait

您可以连续提交其中的 100 个,它们将按顺序 运行 大小为 16 的块。这并不是很有效,但是一次等待 100 个节点有一个空闲任务(所以没有分块),可能需要更长的时间。我当然更喜欢第一个选项,但如果您的管理员不想添加一些 gres,这可能是一个选项。

最有效的方法是@Marcus Boden 建议的 gres 方法。

但如果管理员无法帮助您,您可以在提交脚本的开头添加一小段代码,检查所需的端口是否可用(例如使用netstat 命令)。

如果端口不可用,请使用 scontrol requeue SLURM_JOB_ID. Before requeueing, in order to prevent the job from hitting the same, unavailable, node, you can edit the job to exclude that node: scontrol update jobid=$SLURM_JOB_ID ExcNodeList=$(hostname -s) 重新排队作业.理想情况下,代码应该更聪明一点,从作业中检索当前排除的节点列表并附加当前节点。

另一种选择是修改 scontrol update jobid=$SLURM_JOB_ID StartTime=.... 的工作,将开始时间设置为当前时间加上工作的典型挂钟时间,这样当工作再次符合条件时,工作当前节点上的 运行 将完成。但是当然不能保证该节点不会在此期间被分配到另一个作业。