Slurm 中的可消耗资源

Slurm 使用默认的节点分配插件以独占模式分配节点给作业。这意味着,即使某个作业没有利用节点内的所有资源,另一个作业也无法访问这些资源。节点拥有处理器、内存、交换空间、本地磁盘等资源,而作业消耗这些资源。Slurm 的独占使用默认策略可能导致集群及其节点资源的低效利用。Slurm 的 cons_tres 插件可用于更细粒度地管理资源,如下所述。

使用可消耗可追踪资源插件: select/cons_tres

可消耗可追踪资源(cons_tres)插件已构建为支持多种资源。它可以跟踪主板、插槽、核心、CPU、内存以及任何逻辑处理器与内存的组合:

  • CPU (CR_CPU):作为可消耗资源的 CPU。
    • 没有插槽、核心或线程的概念。
    • 在多核系统中,CPU 将是核心。
    • 在多核/超线程系统中,CPU 将是线程。
    • 在单核系统中,CPU 就是 CPU。
  • 主板 (CR_Board):作为可消耗资源的主板。
  • 插槽 (CR_Socket):作为可消耗资源的插槽。
  • 核心 (CR_Core):作为可消耗资源的核心。
  • 内存 (CR_Memory) 仅作为可消耗资源的内存。 注意:CR_Memory 假设 OverSubscribe=Yes
  • 插槽和内存 (CR_Socket_Memory):作为可消耗资源的插槽和内存。
  • 核心和内存 (CR_Core_Memory):作为可消耗资源的核心和内存。
  • CPU 和内存 (CR_CPU_Memory):作为可消耗资源的 CPU 和内存。

所有 CR_* 参数假设 OverSubscribe=NoOverSubscribe=Force,除了 CR_MEMORY 假设 OverSubscribe=Yes

cons_tres 插件还提供与 GPU 相关的特定功能。

可用于 cons_tres 插件的附加参数:

  • DefCpuPerGPU:每个 GPU 分配的默认 CPU 数量。
  • DefMemPerGPU:每个 GPU 分配的默认内存量。

可用于 cons_tres 插件的附加作业提交选项:

  • --cpus-per-gpu=:每个 GPU 的 CPU 数量。
  • --gpus=:整个作业分配的 GPU 数量。
  • --gpu-bind=:将任务绑定到特定 GPU。
  • --gpu-freq=:请求特定的 GPU/内存频率。
  • --gpus-per-node=:每个节点的 GPU 数量。
  • --gpus-per-socket=:每个插槽的 GPU 数量。
  • --gpus-per-task=:每个任务的 GPU 数量。
  • --mem-per-gpu=:每个 GPU 的内存量。

srun 的 -B 扩展在选择 CR_CPU 或 CR_CPU_MEMORY 时会被节点分配机制忽略。它用于计算总任务数,当未指定 -n 时。

在内存是可消耗资源的情况下,必须在 slurm.conf 中设置 RealMemory 参数以定义节点的实际内存量。

作业提交命令(salloc、sbatch 和 srun)支持选项 --mem=MB--mem-per-cpu=MB,允许用户指定每个节点或每个分配的 CPU 所需的最大实际内存量。在内存是可消耗资源的环境中,此选项是必需的。指定足够的内存非常重要,因为 Slurm 不允许应用程序使用超过请求的实际内存量。--mem 的默认值继承自 DefMemPerNode。有关更多详细信息,请参见 srun(1)。

允许使用 --overcommit-O。当通过使用适当的 TaskPlugin 配置参数启用逻辑处理器固定时,额外的进程将共享分配的资源。

可消耗可追踪资源插件通过 slurm.conf 中的 SelectType 参数启用。

# 示例 slurm.conf 文件摘录
SelectType=select/cons_tres

一般说明

Slurm 的默认 select/linear 插件使用基于连续节点数量的最佳适应算法。

select/cons_tres 插件在整个集群中启用或禁用。

在启用 select/linear 的情况下,正常的 Slurm 行为不会受到干扰。用户在使用 select/cons_tres 插件时看到的主要变化是,当资源允许时,作业可以在节点上共同调度。通用资源(例如 GPU)也可以通过此插件单独跟踪。Slurm 的其余部分,例如 srun 及其选项(除了 srun -s ...)等,不受此插件的影响。从用户的角度来看,Slurm 的工作方式与使用默认节点选择方案时相同。

--exclusive srun 选项允许用户请求独占模式的节点,即使在启用可消耗资源的情况下。有关详细信息,请参见 srun(1)。

srun 的 -s--oversubscribe 与可消耗资源环境不兼容,因此将不被尊重。由于该环境的节点默认是共享的,--exclusive 允许用户获得专用节点。

--oversubscribe--exclusive 选项在作业提交时是互斥的。如果在提交作业时同时设置这两个选项,则所使用的作业提交命令将失败。

CR_Memory、CR_Socket_Memory 和 CR_CPU_Memory 类型可消耗资源的示例

# sinfo -lNe
NODELIST     NODES PARTITION  STATE  CPUS  S:C:T MEMORY
hydra[12-16]     5 allNodes*  ...       4  2:2:1   2007

使用 select/cons_tres 插件与 CR_Memory

示例:
# srun -N 5 -n 20 --mem=1000 sleep 100 &  <-- 正在运行
# srun -N 5 -n 20 --mem=10 sleep 100 &    <-- 正在运行
# srun -N 5 -n 10 --mem=1000 sleep 100 &  <-- 排队并等待资源

# squeue
JOBID PARTITION   NAME   USER ST  TIME  NODES NODELIST(REASON)
 1820  allNodes  sleep sballe PD  0:00      5 (资源)
 1818  allNodes  sleep sballe  R  0:17      5 hydra[12-16]
 1819  allNodes  sleep sballe  R  0:11      5 hydra[12-16]

使用 select/cons_tres 插件与 CR_Socket_Memory(每个节点 2 个插槽)

示例 1:
# srun -N 5 -n 5 --mem=1000 sleep 100 &        <-- 正在运行
# srun -n 1 -w hydra12 --mem=2000 sleep 100 &  <-- 排队并等待资源

# squeue
JOBID PARTITION   NAME   USER ST  TIME  NODES NODELIST(REASON)
 1890  allNodes  sleep sballe PD  0:00      1 (资源)
 1889  allNodes  sleep sballe  R  0:08      5 hydra[12-16]

示例 2:
# srun -N 5 -n 10 --mem=10 sleep 100 & <-- 正在运行
# srun -n 1 --mem=10 sleep 100 & <-- 排队并等待资源

# squeue
JOBID PARTITION   NAME   USER ST  TIME  NODES NODELIST(REASON)
 1831  allNodes  sleep sballe PD  0:00      1 (资源)
 1830  allNodes  sleep sballe  R  0:07      5 hydra[12-16]

使用 select/cons_tres 插件与 CR_CPU_Memory(每个节点 4 个 CPU)

示例 1:
# srun -N 5 -n 5 --mem=1000 sleep 100 &  <-- 正在运行
# srun -N 5 -n 5 --mem=10 sleep 100 &    <-- 正在运行
# srun -N 5 -n 5 --mem=1000 sleep 100 &  <-- 排队并等待资源

# squeue
JOBID PARTITION   NAME   USER ST  TIME  NODES NODELIST(REASON)
 1835  allNodes  sleep sballe PD  0:00      5 (资源)
 1833  allNodes  sleep sballe  R  0:10      5 hydra[12-16]
 1834  allNodes  sleep sballe  R  0:07      5 hydra[12-16]

示例 2:
# srun -N 5 -n 20 --mem=10 sleep 100 & <-- 正在运行
# srun -n 1 --mem=10 sleep 100 &       <-- 排队并等待资源

# squeue
JOBID PARTITION   NAME   USER ST  TIME  NODES NODELIST(REASON)
 1837  allNodes  sleep sballe PD  0:00      1 (资源)
 1836  allNodes  sleep sballe  R  0:11      5 hydra[12-16]

使用可消耗资源插件的节点分配示例

以下示例说明了四个作业在集群中的不同分配方式,使用(1)Slurm 的默认分配方法(独占模式)和(2)将处理器作为可消耗资源的方法。

重要的是要理解,下面列出的示例是一个人为的示例,仅用于说明将 CPU 作为可消耗资源的用法。作业 2 和作业 3 要求节点数量等于处理器数量。这通常是因为每个节点的一个任务需要所有内存、磁盘空间等。瓶颈不会是处理器数量。

尝试在每个节点上执行多个作业几乎肯定会严重影响并行作业的性能。将 CPU 作为可消耗资源的最大受益者将是串行作业或具有适度并行性的作业,这些作业可以有效地共享资源。在许多处理器数量较大的系统中,作业通常运行的任务数比处理器少一个,以最小化内核和守护进程的干扰。

示例集群由 4 个节点组成(总共 10 个 CPU):

  • linux01(有 2 个处理器),
  • linux02(有 2 个处理器),
  • linux03(有 2 个处理器), 和
  • linux04(有 4 个处理器)。

这四个作业如下:

  • [2] srun -n 4 -N 4 sleep 120 &
  • [3] srun -n 3 -N 3 sleep 120 &
  • [4] srun -n 1 sleep 120 &
  • [5] srun -n 3 sleep 120 &

用户按上述顺序启动它们。

使用 Slurm 的默认节点分配(非共享模式)

这四个作业已启动,3 个作业现在处于待处理状态,等待分配资源。只有作业 2 正在运行,因为它在所有 4 个节点上使用一个 CPU。这意味着 linux01 到 linux03 每个都有一个空闲 CPU,而 linux04 有 3 个空闲 CPU。

# squeue
JOBID PARTITION   NAME  USER  ST  TIME  NODES NODELIST(REASON)
    3       lsf  sleep  root  PD  0:00      3 (资源)
    4       lsf  sleep  root  PD  0:00      1 (资源)
    5       lsf  sleep  root  PD  0:00      1 (资源)
    2       lsf  sleep  root   R  0:14      4 linux[01-04]

一旦作业 2 完成,作业 3 被调度并在 linux01、linux02 和 linux03 上运行。作业 3 仅在这 3 个节点上使用一个 CPU。作业 4 可以分配到剩余的空闲节点(linux04),因此作业 3 和作业 4 可以在集群上并行运行。

作业 5 必须等待空闲节点才能运行。

# squeue
JOBID PARTITION   NAME  USER  ST  TIME  NODES NODELIST(REASON)
    5       lsf  sleep  root  PD  0:00      1 (资源)
    3       lsf  sleep  root   R  0:11      3 linux[01-03]
    4       lsf  sleep  root   R  0:11      1 linux04

一旦作业 3 完成,作业 5 被分配资源并可以运行。

独占模式调度策略的优点是作业可以获得分配节点的所有资源,以实现最佳的并行性能。缺点是作业可能会占用大量未使用的资源,并且这些资源无法与其他作业共享。

使用处理器可消耗资源的方法

我们将再次通过使用 cons_tres 插件和 CPU 作为可消耗资源来运行相同的场景。squeue 的输出显示我们有 4 个作业中有 3 个被分配并正在运行。这比默认的 Slurm 方法多了 2 个正在运行的作业。

作业 2 正在 linux01 到 linux04 节点上运行。作业 2 的分配与 Slurm 的默认分配相同,即它在 4 个节点上使用一个 CPU。一旦作业 2 被调度并运行,节点 linux01、linux02 和 linux03 仍然每个有一个空闲 CPU,而节点 linux04 有 3 个空闲 CPU。此方法与上述独占模式方法之间的主要区别在于,节点内的空闲 CPU 现在可以分配给其他作业。

重要的是要注意,分配 并不意味着 超分配。可消耗资源方法跟踪每个可用资源(在我们的案例中是 CPU)必须专门分配给特定作业的数量。这使我们能够防止每个节点的资源(CPU)超分配。

一旦作业 2 正在运行,作业 3 被调度到节点 linux01、linux02 和 linux03(在每个节点上使用一个 CPU),作业 4 被调度到 linux04 上的一个剩余空闲 CPU。

作业 2、作业 3 和作业 4 现在在集群上并行运行。

# squeue
JOBID PARTITION   NAME  USER  ST  TIME  NODES NODELIST(REASON)
    5       lsf  sleep  root  PD  0:00      1 (资源)
    2       lsf  sleep  root   R  0:13      4 linux[01-04]
    3       lsf  sleep  root   R  0:09      3 linux[01-03]
    4       lsf  sleep  root   R  0:05      1 linux04

# sinfo -lNe
NODELIST     NODES PARTITION       STATE CPUS MEMORY TMP_DISK WEIGHT FEATURES REASON
linux[01-03]     3      lsf*   allocated    2   2981        1      1   (null) none
linux04          1      lsf*   allocated    4   3813        1      1   (null) none

一旦作业 2 完成,待处理的作业 5 被分配可用资源并运行,如下所示:

# squeue
JOBID PARTITION   NAME  USER  ST  TIME  NODES NODELIST(REASON)
   3       lsf   sleep  root   R  1:58      3 linux[01-03]
   4       lsf   sleep  root   R  1:54      1 linux04
   5       lsf   sleep  root   R  0:02      3 linux[01-03]
# sinfo -lNe
NODELIST     NODES PARTITION       STATE CPUS MEMORY TMP_DISK WEIGHT FEATURES REASON
linux[01-03]     3      lsf*   allocated    2   2981        1      1   (null) none
linux04          1      lsf*        idle    4   3813        1      1   (null) none

作业 3、作业 4 和作业 5 现在在集群上并行运行。

# squeue
JOBID PARTITION   NAME  USER  ST  TIME  NODES NODELIST(REASON)
    5       lsf  sleep  root   R  1:52      3 linux[01-03]

作业 3 和作业 4 已完成,作业 5 仍在 linux[01-03] 节点上运行。

可消耗资源调度策略的优点在于作业吞吐量可以显著增加。集群的整体作业吞吐量和生产力提高,从而减少用户等待作业完成的时间,同时提高集群的整体使用效率。缺点是用户默认没有整个节点专用于他们的作业。

我们已将 --exclusive 选项添加到 srun(有关更多详细信息,请参见 srun(1)),允许用户指定希望以独占模式分配节点。这是为了满足可能有 mpi/threaded/openMP 程序的用户,这些程序将利用节点上的所有 CPU,但每个节点只需要一个 mpi 进程。

最后修改于 2023 年 5 月 18 日