最近要用到集群,了解到SLURM集群资源和作业管理软件,简单介绍,详细可参考下方链接

简介

用途

​ Slurm(Simple Linux Utility for Resource Management, http://slurm.schedmd.com/ )是开源的、具有容错性和高度可扩展的Linux集群超级计算系统资源管理和作业调度系统。超级计算系统可利用Slurm对资源和作业进行管理,以避免相互干扰,提高运行效率。所有需运行的作业,无论是用于程序调试还是业务计算,都可以通过交互式并行 srun 、批处理式 sbatch 或分配式 salloc 等命令提交,提交后可以利用相关命令查询作业状态等。

架构

​ Slurm采用slurmctld服务(守护进程)作为中心管理器用于监测资源和作业,为了提高可用性,还可以配置另一个备份冗余管理器。各计算节点需启动slurmd守护进程,以便被用于作为远程shell使用:等待作业、执行作业、返回状态、再等待更多作业。slurmdbd(Slurm DataBase Daemon)数据库守护进程(非必需,建议采用,也可以记录到纯文本中等),可以将多个slurm管理的集群的记账信息记录在同一个数据库中。还可以启用slurmrestd(Slurm REST API Daemon)服务(非必需),该服务可以通过REST API与Slurm进行交互,所有功能都对应的API。用户工具包含 srun 运行作业、 scancel 终止排队中或运行中的作业、 sinfo 查看系统状态、 squeue 查看作业状态、 sacct 查看运行中或结束了的作业及作业步信息等命令。 sview 命令可以图形化显示系统和作业状态(可含有网络拓扑)。 scontrol 作为管理工具,可以监控、修改集群的配置和状态信息等。用于管理数据库的命令是 sacctmgr ,可认证集群、有效用户、有效记账账户等。

术语

  • 节点

​ Hea Node:头节点、管理节点、控制节点,运行slurmctld管理服务的节点。

​ Compute Node:计算节点,运行作业计算任务的节点,需运行slurmd服务。

​ Login Node:用户登录节点,用于用户登录的节点。

​ SlurmDBD Node:SlurmDBD节点、SlurmDBD数据库节点,存储调度策略、记账和作业等信息的节点,需运行slurmdbd服务。

​ 客户节点:含计算节点和用户登录节点。

  • 用户

​ account:账户,一个账户可以含有多个用户。

​ user:用户,多个用户可以共享一个账户。

​ bank account:银行账户,对应机时费等。

  • 资源

​ GRES:Generic Resource,通用资源。

​ TRES:Trackable RESources,可追踪资源。

​ QOS:Quality of Service,服务质量,作业优先级。

​ association:关联。可利用其实现,如用户的关联不在数据库中,这将阻止用户运行作业。该选项可以阻止用户访问无效账户。

​ Partition:队列、分区。用于对计算节点、作业并行规模、作业时长、用户等进行分组管理,以合理分配资源。

规划准备

​ 集群名:MyCluster

管理节点admin:

  • 内网IP:191.168.1.254

  • /opt/ 目录:通过NFS网络共享给其它节点使用

  • 配置文件: /etc/slurm/ 目录下的 cgroup.confslurm.confslurmdbd.conf 等文件

  • 需要启动(按顺序)的守护进程服务:

    1. 通信认证:munge
    2. 系统数据库:mariadb(也可采用文本保存,更简单,本文不涉及)
    3. Slurm数据库:slurmdbd
    4. 主控管理器:slurmctld

数据库节点(运行slurmdbd服务)admin:

  • 可与管理节点共用,本文档与管理节点共用

用户登录节点login:

  • 内网IP:191.168.1.250
  • /opt/ 目录:通过NFS服务共享管理节点上的 /opt/ 目录

计算节点node[1-10]:

  • 内网IP:191.168.1.[1-10]

  • /opt/ 目录:通过NFS服务共享管理节点上的 /opt/ 目录

    • 需要启动(按顺序)的服务:

      通信认证:mungeSlurm数据库:slurmdbd

使用

编写slurm脚本

#!/bin/bash
#SBATCH -J test # 作业名是 test
#SBATCH -p defq # 提交到 默认的defq 队列
#SBATCH -N 2 # 使用2个节点
#SBATCH --ntasks-per-node=6 # 每个节点开启6个进程
#SBATCH --cpus-per-task=1 # 每个进程占用一个 cpu 核心
#SBATCH -t 50:00 # 任务最大运行时间是 50 分钟
#SBATCH --gres=gpu:1 # 如果是gpu任务需要在此行定义gpu数量,此处为1
module load openmpi/gcc/64/1.10.7
mpirun ./a.out # 执行我编译的的 ./a.out 程序

​ 脚本的第一行指定了这个脚本的解释器为 bash。每次编写脚本 都必须写上这一行。之后有 # 开头的若干行表示 SLURM 作业的设置区域,它 告诉工作站运行任务的详细设定:它被提交到defq 队列当中,申请 2 个节点的 总共12 个 核心,每个节点调用1个gpu,限制任务最大运行时间是50分钟, 它的主体内容就是在当前目录执行我编译好的程序 a.out。

​ 上面的例子是最简单的批处理任务,较为完整的设置后面会介绍。另外用户也可提交交互式任务来完成计算。

提交任务

​ 在提交任务之前,先使用 sinfo 查看可用资源情况。

$ sinfo
PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
defq* up infinite 21 idle node[001-021]
gpu up infinite 1 idle node021

​ 我们看到目前的 defq 分区处于空闲状态(idle),任务可以提交。准备好 SLURM 脚本之后,使用

sbatch job.sh

​ 就可以将刚才的任务提交上去,这里 sbatch 是提交 SLURM 脚本的命令。 如果工作站有空闲资源,那么我的程序将会被放在某2个节点的12个核心上运行。我只需要等待我的程序完成即可。

​ 提交完成后,会输出以下提示Submitted batch job 416

​ 数字编号即为当前任务编号,这个ID非常重要,查询 诊断 删除都需要此ID号

​ 使用 sbatch 时如果指定的参数不当会导致提交失败。使用 squeue 命令可以查询 目前正在运行的任务,通过查询的结果来判断提交是否成功。

[test@admin ~]$ sbatch sl.sh
Submitted batch job 416
[test@admin ~]$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
416 defq arraytest R 4:17 2 node[01-02]

​ 在以上输出中,sbatch 返回信息是Submitted batch job 416 这表示我的 任务已经成功提交任务(作业/jobid)号是 416。而 squeue 显示我提交的任务的具体信息,在这里 看到我的任务被放到 defq 队列上运行,占用 2 个节点 node01,node02,状态(ST)是运行 状态(R),并且已经运行了 4分17秒。

输出文件

​ 当我的程序完成后,我应该到我指定的文件中去寻找程序的输出。 系统默认会将标准输出文件和标准错误文件生成到调用 sbatch 的目录下(提交当前任务的目录)。默认的 文件名是 slurm-.out ,其中 JOBID 是作业号。如果在 SLURM 脚本中使用 了 -o 选项,则这些文件会被生成到用户所指定的目录下。

​ 这里讲的输出文件只包含程序运行时打印在屏幕上的内容,即标准输出流和标准错误流。 程序的其他输出(例如 MATLAB 存储的 .mat 文件,python 输出的图像)则需要用户 手动将这些数据存下来。若不手动指定,这些数据将会丢失。

​ 总结起来,在集群上进行运算的步骤如下:

  • 登录主节点,准备程序和数据。
  • 编写 SLURM 脚本,设置作业属性(例如占用的资源,最长运行时间)。
  • 检查可用资源,提交作业脚本,检查任务状态(使用 squeue 和 sinfo )。
  • 等待运行结束,验收结果。

在slurm脚本中使用module

​ module 命令仅作用在当前节点上,如果使用 SLURM 脚本提交任务,那么实际运行任务的 节点和当前节点是不同的,因此方便的做法是将 module 命令一并写在 SLURM 脚本中。

#!/bin/bash
#SBATCH -J test # 作业名是 test
#SBATCH -p defq # 提交到 默认的defq 队列
#SBATCH -N 2 # 使用2个节点
#SBATCH --ntasks-per-node=6 # 每个节点开启6个进程
#SBATCH --cpus-per-task=1 # 每个进程占用一个 cpu 核心
#SBATCH -t 50:00 # 任务最大运行时间是 50 分钟
#SBATCH --gres=gpu:1 # 如果是gpu任务需要在此行定义gpu数量,此处为1
module load openmpi/gcc/64/1.10.7
mpirun ./a.out # 执行我编译的的 ./a.out 程序

定制你自己的默认载入 module

​ 当你登录系统时,系统会默认载入一些 module。如果这些 module 不是你需要的,或者你 需要载入更多的 module,那么请直接在个人 HOME 目录下的 .bashrc 文件的 最后添加

module load <module name>

​ 即可。每个 module 的添加单独占一行。这样每次你登录系统之后系统就会自动加载你指定的 module,也非常方便管理

​ 更改 .bash_profile 文件的同时,在你运行 SLURM 任务时也会自动载入你添加的这些 module, 因此无需在 SLURM 脚本中再次添加 module 命令!

提交交互式任务

​ 交互式任务是一种特殊的队列任务,在该模式下,用户可以直接登录到计算节点,此后 所有的操作都在这个节点上进行。这个功能主要是方便用户在服务器上调试程序, 以便能够实时看到程序的输出。

直接申请资源方式

​ 我们需要使用 salloc 命令来分配交互式任务所需的资源,它的语法为

$ salloc [申请资源]

​ 其中,用户需要以选项的方式指定申请的资源,这些选项与 SLURM 脚本中的选项基本 相同。常用选项为:

-N <节点数量>
-n <总进程数>
--ntasks-per-node=<每节点的进程数>
--cpus-per-task=<每进程的CPU核心数>
--gres=gpu:<每节点的GPU卡数>
-t <最长运行时间>
-p <指定使用的队列>
--qos=<指定使用的 QoS>

​ 例如,可以使用如下方式申请资源:

$ salloc -N 1 --cpus-per-task=4 -t 5:00

​ 执行成功后,SLURM 会给你一个新的 Shell,注意此时用户所在节点仍为主节点,但是如使用mpirun运行计算任务,会自动提交到申请的节点上运行,或者ssh到申请的计算节点上运行

​ 在策略配置略微严格的集群中,如计算节点没有当前用户已提交的的任务,是被禁止ssh过去的

[test@admin ~]$ salloc -N 1 --cpus-per-task=4 -t 5:00
salloc: Granted job allocation 419
[test@admin ~]$ squeue
JOBID PARTITION NAME USER ST TIME NODES
NODELIST(REASON)
419 defq bash test1 R 0:06 1 node021
[test@admin ~]$ ssh node021 # 这就是 salloc 分配的节点
Last login: Thu Jan 23 01:45:41 2020 from admin.cm.cluster

​ 如上所示,执行 salloc 后,SLURM 会自动分配作业号并可以通过squeue 查看哪个节点是可用的。成功 获取资源后,你会进入到一个新的环境,此时用户可以直接切换到目标节点 comput1 执行运算任务。

​ 交互式计算使用完毕后,先使用 exit 退出节点,再执行 exit 退出 SLURM 分配 的 Shell,可结束这次交互式任务。SLURM 会提示你交互式任务的资源已经被释放。

[test@node021 ~]$ exit # 这一步是退出 node021
logout
Connection to node021 closed.
[test1@bsbii ~]$ exit # 这一步是退出 salloc 分配的 shell
exit
salloc: Relinquishing job allocation 419 # 退出的同时也释放了资源

​ 用户会重新回到 管理节点原始命令行下进行操作。

申请资源并自动分类计算节点终端方式

​ 部分管理较为严格的集群中,管理员会禁止用户通过ssh登录到计算节点,如遇到特殊情况必须要在计算节点的终端运行,可以通过srun 来申请资源并自动开启一个计算节点终端

[test@admin ~]$ srun -N 1 --cpus-per-task=4 -t 5:00 --gres=gpu:1 --pty bash
[test@node021 ~]$
[test@node021 ~]$ nvidia-smi
Sat Feb 1 12:17:12 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.87.01 Driver Version: 418.87.01 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla V100-PCIE... On | 00000000:18:00.0 Off | 0 |
| N/A 31C P0 25W / 250W | 0MiB / 32480MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+

​ 通过以上方式,申请了相关资源并且开启了一个计算节点终端

​ 注意事项

  • 如果 salloc 命令无响应,可能是目前所剩计算资源小于申请的资源,需要检查你的填写参数或等计算任务少的时候再试。
  • 原则上管理节点只能进行登录,修改文件,编译程序等任务。严禁在管理节点上直接运行需要大量运算的程序。管理员有权在不经过用户同意的情况下强行中止长时间运行在管理节点上的大型程序(占用较多 CPU 或者内存的程序)。

​ 建议

  • salloc 建议用作多机并行的任务,这样可以很方便快速地开始计算
  • srun 开启计算节点终端的方式,建议用作单机测试和计算的任务,比如
    1.申请资源并分配一个计算节点终端后,打开软件的图形界面并调用本地资源
    2.申请资源并分配一个计算节点终端后,开启一个jupyter的后台任务
    3.申请资源并分配一个计算节点终端后,直接调用本地资源计算

提交批处理任务

​ 在工作站提交批处理任务需要编写 SLURM 脚本,以便明确申请的资源以及所要运行的程序。

查看可用资源

​ 在提交任务之前,务必检查一下各个节点的状态,例如资源是否充足,当前有多少正在执 行的任务等。

[cmsupport@admin ~]$ sinfo
PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
defq* up infinite 1 mix node021
defq* up infinite 20 idle node[001-020]
gpu up infinite 1 mix node021

​ 如上所示,使用 sinfo 可粗略查看所有分区的节点信息,注意 ‘‘STATE’’ 一栏的输出 若为 ‘‘idle’’ 表示该节点处于闲置状态,若为 ‘‘alloc’’ 表示该节点已经没有多余的 资源了,若为 ‘‘mix’’ 表示该节点有人在占用,但是仍然有剩余资源。

​ 对于 gpu 队列的节点 node021,如果显示 ‘‘mix’’ 表示部分资源被占用,可能出现 GPU 卡都被占用但是有空闲 CPU 核心的情况。此时我们需要这个节点更详细的信息。可以使用 scontrol show node <节点名> 命令。

[cmsupport@admin ~]$ scontrol show node node021
NodeName=node021 Arch=x86_64 CoresPerSocket=16
CPUAlloc=2 CPUTot=64 CPULoad=0.06
AvailableFeatures=(null)
ActiveFeatures=(null)
Gres=gpu:2
NodeAddr=node021 NodeHostName=node021 Version=18.08
OS=Linux 3.10.0-957.1.3.el7.x86_64 #1 SMP Thu Nov 29 14:49:43 UTC 2018
RealMemory=192030 AllocMem=0 FreeMem=183286 Sockets=2 Boards=1
State=MIXED ThreadsPerCore=2 TmpDisk=212445 Weight=1 Owner=N/A MCS_label=N/A
Partitions=defq,gpu
BootTime=2019-12-12T18:43:16 SlurmdStartTime=2020-02-13T00:15:07
CfgTRES=cpu=64,mem=192030M,billing=64,gres/gpu=2
AllocTRES=cpu=2,gres/gpu=2
CapWatts=n/a
CurrentWatts=0 LowestJoules=0 ConsumedJoules=0
ExtSensorsJoules=n/s ExtSensorsWatts=0 ExtSensorsTemp=n/s

​ 如上所示, sinfo 显示 gpu 队列的 node021 状态是 ‘‘mix’’,但是使用 scontrol 命令查看发现已经占用的资源为 AllocTRES=cpu=2,gres/gpu=2,即占用 了 2个 CPU 核心和 2 块 GPU 卡。GPU 卡已经全部占用,这个节点将 无法运行需要 GPU 的任务。但仍然可运行纯 CPU 任务。

​ 此外,管理员还提供了3个有用的命令 snode pestat 用于查看各个节点的状态 与集群所有任务的运行情况。

[cmsupport@admin ~]$ snode
JOBID USER NAME CPUS NODES TRES_PER_NODE PARTITION NODELIST
459 cmsupport bash 2 1 gpu:2 defq
node021

编写slurm脚本

#!/bin/bash
#SBATCH -J test # 作业名是 test
#SBATCH -p defq # 提交到 defq 队列
#SBATCH -N 2 # 使用2个节点
#SBATCH --ntasks-per-node=6 # 每个节点开启6个进程
#SBATCH --cpus-per-task=1 # 每个进程占用一个 cpu 核心
#SBATCH -t 50:00 # 任务最大运行时间是 50 分钟 (非必需项)
#SBATCH --gres=gpu:1 # 如果是gpu任务需要在此行定义gpu数量,此处为1
#SBATCH -w node01 # 指定某个节点 (非必需项)
# 加载运行环境
module load openmpi/gcc/64/1.10.7
# 输入要执行的命令
mpirun ./a.out # 执行我编译的的 ./a.out 程序

​ 其中,第一行是固定的,表示使用 /bin/bash 来执行脚本。其余的说明如下

  • 申请时请写对队列 (Partition) ,由于不同的队列硬件配置不同。
  • 申请的资源不要超过当前队列的最大值,建议使用 scontrol 命令查看队列的剩余资源数。确定申请 CPU 核心数量之前,请确认你的程序是否真的需要这些计算资源。如果 程序的并行程度不高,申请过多的 CPU 核心数会造成资源的浪费(多数 CPU 占用率会较 低),并且会影响他人使用。
  • 实际在每个节点上分配的 CPU 数量由 –ntasks-per-node 和 –cpus-per-task 参数共同决定。默认情况下二者都是 1。一般来讲,多进程的程序需要更改 –ntasks-per-node ,多线程的程序需要更改 –cpus-per-task 。各位用户请根据 自己需求进行设置。
  • 任务最长时间的设置格式是 DD-HH:MM:SS ,例如一天又 15 小时写作 1-15:00:00 。 如果高位为0 可省略。如果不写任务最长时间,则任务的最长时间默认为对应队列 (Partition) 的默认时间。

​ 以上的所有 #SBATCH 属性均可以不设置,当缺少某属性时,系统将使用默认值。

​ 请在使用时估计自己任务的开销,适量申请计算资源,避免造成资源的浪费。

常见的计算软件/软件库的启动命令

​ 以下列出集群中常见的软件启动命令,可以作为手动编写 SLURM 脚本的参考,也可以 作为交互式计算的使用参考。

​ 以命令行模式运行 MATLAB

$ matlab -nodesktop -nosplash -nodisplay

​ 使用 MATLAB 运行 m 脚本

$ matlab -nodesktop -nosplash -nodisplay -r "MATLAB 脚本名,不带 m 后缀"

​ 注意:MATLAB 脚本不能像其他语言(如 python,bash)等使用 shebang 来指定解释器, 因此执行一个 M 文件需要使用 MATLAB 内置命令。-r 参数的含义其实并不是“执行 一个脚本”,而是因为在MATLAB 的命令行中,输入命令可以等效于执行同名的脚本, 因此才使用这种方式。

​ 使用 R 运行 R 脚本

$ Rscript <脚本名>

​ 使用 python 运行 py 脚本

$ python <脚本名>

提交任务

​ 将 SLURM 脚本编写完毕并上传工作站后(或直接在工作站编辑),进入 SLURM 脚本的 目录,使用

$ sbatch <SLURM 脚本文件名>

​ 即可提交任务

​ 注意,如果参数设置不当 sbatch 命令会提交失败,此时需要检查你的参数并修改成正确的版本。用户需要使用 squeue 检查作业运行情况,若作业是因为参数不当而没有 运行,则需要修改 SLURM 脚本。

​ 例如,执行 sbatch 后发现如下内容:

[cmsupport@admin playground]$ sbatch run.slurm
sbatch: error: Batch job submission failed: Requested node configuration is not
available

​ 说明指定的队列内没有所需的资源

​ 有时 sbatch 命令会显示正常提交,但是任务始终无法运行,此时需要使用 squeue 查看任务排队的详细情况。

[cmsupport@admin playground]$ sbatch run.slurm
Submitted batch job 55
[cmsupport@admin playground]$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
55 cpu test liuhy PD 0:00 1 (PartitionTimeLimit)

​ 此时 55 号作业的状态为 PD(Pending),即“被挂起”,最后一列显示了原因是 PartitionTimeLimit,即申请的运行时间已经超过了该队列允许运行的最大时间,任务 永远不会运行。此时需要先使用 scancel 命令(详见下面的说明)取消任务,然后 修改 SLURM 脚本使得参数正确。

查看任务状态

​ 作业提交完毕后,可使用 squeue 命令查看任务状态。

[cmsupport@admin playground]$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
55 cpu test liuhy PD 0:00 1 (PartitionTimeLimit)
54 cpu test liuhy R 0:15 1 comput1

​ 如上所示,可显示目前任务号,所在队列,任务状态,已经运行时间,以及运行的节点。 如果任务处于挂起(PD)状态,则显示任务被挂起的原因。用户可以根据这个原因来判断 自己的作业脚本是否写对了。

​ 除此之外,使用 squeue 配合不同参数可以过滤显示的内容,以便能看到你感兴趣的 结果。某些参数可以相互组合。

  • squeue -l : 以长列表显示更多信息。
  • squeue -u username : 仅显示属于用户 username 的任务。
  • squeue -t state : 仅显示处于 state 状态的任务。
    删除任务
  • scancel jobid : 删除 jobid 的作业。
  • scancel -u username : 删除 username 的全部作业。
  • scancel -s state : 删除处于 state 状态的作业。

​ 注意:用户只能删除自己的作业,不能删除别人的作业。

集群计算常用范例

​ 我是一个GPU用户,如何使用集群的GPU资源来进行深度学习计算

​ 这部分需要注意的是,集群内会装有不同版本的cuda,tensorflow等库和计算软件,请load对应的模块进行计算

#!/bin/bash
#SBATCH -J test
#SBATCH -p defq
#SBATCH -N 1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=6
#SBATCH --gres=gpu:1
module load tensorflow-py36-cuda10.1-gcc/1.14.0
module load openmpi/cuda/64/3.1.4
cd tensorflow_test
python tf_cnn_benchmarks.py --num_gpus=1 --batch_size=32 --model=resnet50 -
-variable_update=parameter_serve

常用命令和参数速查

​ 调度器部分

​ 最常用的 SLURM 命令:
​ sacct: 查看历史任务信息
​ salloc: 分配资源
​ sbatch: 提交批处理任务
​ scancel: 取消任务
​ scontrol: 系统控制
​ sinfo: 查看节点与队列状态
​ squeue: 查看任务状态
​ srun: 执行任务

​ slurm 内部环境变量
​ SLURM_NPROCS 任务要加载的总进程数
​ SLURM_TASKS_PER_NODE 每节点要加载的进程数
​ SLURM_JOB_ID 任务的 JobID
​ SLURM_SUBMIT_DIR 提交任务时的工作目录
​ SLURM_JOB_NODELIST 任务分配的节点列表
​ SLURM_JOB_CPUS_PER_NODE 每个节点上分配给任务的总 CPU核心数
​ SLURM_JOB_NUM_NODES 作业分配的节点数