Skip to main content Link Menu Expand (external link) Document Search Copy Copied

这是一篇比较长的教程. 但你仍然需要仔细阅读以确保能正确的在集群上运行程序.

如何利用SLURM在集群上运行程序

Last update: April 27, 2024

服务器上已经有很多用户在运行程序了, 你不可以和其他人一起抢占资源 (最终导致炸服). 另外, 我们的登陆节点性能也不如计算节点好(一个节点通常指一台机器). 我们的服务器集群使用 SLURM, 一套自动化资源分配的作业调度工具, 帮助你提交作业到计算节点上运行. 当你的程序需要很长的运行时间或者很大的内存占用时, 请使用 SLURM 提交程序. 下文介绍了如何使用 SLURM 提交程序.

我们以对其他用户可能造成的影响来衡量一个任务是否适合在登录节点临时运行.

例如, 以下是你可以在登录节点上临时运行的程序:

  1. 已知仅使用极少数核心的程序 (例如 C, C++ 程序默认为1核, 不调用 numpy, pandas 等库的简单 Python 程序), 不超过10分钟
  2. 已知使用半数左右核心的程序 (例如经过手动控制并行程度的 C, C++ 程序), 不超过3-5分钟
  3. 可能会使用全部核心的程序 (例如 MATLAB, 涉及 numpy, pandas 等并行计算库的 Python 程序), 不超过1分钟

例如, 以下是你必须要去计算节点上运行的程序:

  1. 预计可能会使用超过 32G 内存的程序
  2. 预计运行时长超过 10 分钟的程序
  3. 预计其中计算密集部分超过 1 分钟的程序

user-topology

申请资源与提交作业

将你想要运行的一条或多条指令 (例如执行一个Python脚本) 称为作业 (job). SLURM 提供了运行作业的三种方式:

  • srun: 将你当前要运行的一条指令提交到计算节点上运行. 优点是最容易使用, 缺点是只能运行一行代码 (因此无法提前设置环境变量等). 如果你想要运行的命令一行不够, 比如需要在运行命令之前加载模块, 或者设置环境变量等, 可以用下面的 sallocsbatch.
  • salloc: 为需要实时处理的作业分配资源, 系统会为你分配一个或多个计算节点, 然后你可以登陆到计算节点上, 使用交互式命令行. 这一用法适用于需要互动处理的作业.
  • sbatch: 提交作业脚本, 系统会为你分配一个或多个计算节点, 运行你的作业. 这一用法适用于放在后台慢慢跑的作业.

每个用户可以同时启动的任务数量不是无限的. 我们有一个 核时limit 来控制用户的新任务是否允许开始运行.

当前 limit: (48 * 24) 核时

计算方法: 对该用户所有运行中任务的 核数乘以预计完成所剩余的时间 求和, 得到当前预计剩余所需核时.

  1. 当你提交的新任务设定的完成时间和核数超过了 limit, 则该任务无法运行. 此时需要减少核数或者设定的时间上限.
  2. 新提交的任务所预期的核时如果会使当前运行任务总核时超过 limit, 则该任务会被强制排队, 直到你已经运行的任务完成, 或占用的核时足以让新任务开始运行.

srun

官方文档: https://slurm.schedmd.com/srun.html

直接在你要运行的程序前加一个 srun, slurm 就会自动帮你把这个程序放到可用的计算节点上运行. 比如, 原本需要运行 python3 helloworld.py, 现在就可以输入

srun python3 helloworld.py

这个任务就会由计算节点执行, 你并不会感觉到和你直接在登录节点(或者你自己的电脑上)执行命令有什么区别, 但实际上所有的运算都是由计算节点完成的, 登录节点只负责把你的命令传达给计算节点.

注意: srun, salloc, sbatch 实际上都有默认的任务执行时间上限. 我们集群的设置是 6 小时. 超出 6 小时的任务会被强制掐断. 如果需要更长的时间需要自己指定运行时间参数, 见下文.

在不添加任何参数的情况下, srun, salloc, sbatch 的计算资源仅仅只有单核, 并且 不会使用GPU. 对于会默认并行的程序来说 (例如Python, MATLAB), 你可能会反而觉得速度不如在登录节点上测试的时候快. 这是因为申请的资源太少了. 你需要指定额外的参数来确定你所需要的核数.

salloc

编写自己的程序, 在跑大规模的测试例子之前通常需要经历在小规模例子上的 debug 环节. 这时候, 为了验证自己的程序能正常运行, 你往往会需要在可以交互的环境下尝试运行程序 -> 观察错误 -> 修改程序 -> 再次运行.

虽然, 非常小的例子 (例如:运行时长仅仅几秒钟的程序) 可以在登录节点上临时测试, 但更多的时候, 你需要在计算节点上测试你的程序.

使用 salloc 可以向 SLURM 申请计算资源, 然后你可以登录到计算节点上进行你的测试 (在命令行里你可以看到你现在在哪台机器上).

aduser@loginNode:~$ salloc
salloc: Granted job allocation 2984
salloc: Waiting for resource configuration
salloc: Nodes bigMem1 are ready for job
aduser@loginNode:~$ ssh bigMem1 -p 10888
... after some time ...
aduser@bigMem1:~$ exit
logout
Connection to 192.168.2.11 closed.
aduser@loginNode:~$ exit
exit
salloc: Relinquishing job allocation 2984
salloc: Job allocation 2984 has been revoked.

首先, 用 salloc 申请资源, 然后通过 ssh 加端口 -p 10888 登录到分配的计算节点上. 例如: ssh bigMem1 -p 10888.

不要忘记加上端口号. 不加端口号的 ssh bigMem1 会收到报错提示: ssh: connect to host bigmem1 port 22: Connection refused.

输入一次 exit 便可回退到登陆节点. 通过 ssh bigMem1 -p 10888 重新进入计算节点.

如果不再需要计算资源了, 再输入一次 exit 将任务结束.

请务必记得结束任务, 避免占用不使用的资源. 默认的任务执行时间上限是 6 小时. 不合理的占用会被管理员提醒.

salloc 会创建一个新的 bash 环境, 因此你在登陆节点上加载的模块和设置的环境变量都需要重新加载和设置.

一些集群会禁止使用 ssh xx 的形式登录计算节点. 此时可以尝试 srun --jobid=xx --pty /bin/bash 来登录计算节点.

另可参考: SLURM 官方文档对 salloc 的介绍 https://slurm.schedmd.com/salloc.html

sbatch

当你想要执行的不止一条命令, 或者执行的命令需要非常久才能完成, 此时需要使用 sbatch 提交你的任务.

把所有需要运行的命令写进一个脚本里, 然后通过 sbatch 提交. 脚本就是平时的 shell 脚本 (入门教程中见过的 shell 指令都可以在里面使用), 但这个脚本必须以 #!/bin/bash 开头. 例如我们创建了一个叫做 job.sh 的文件包含以下内容:

#!/bin/bash
module load MATLAB
matlab -batch "testMatlab"

接下来, 用 sbatch job.sh 提交作业. 屏幕上会打印 Submitted batch job ###, 其中 ### 是你的作业 id. 当作业结束后, 结果会输出到当前目录下的 slurm-###.out, 如果作业产生了错误信息, 会输出到 slurm-###.err.

salloc 不同的是, sbatch 会继承你在登陆节点上加载的模块和设置的环境变量.

另可参考: SLURM 官方文档对 sbatch 的介绍 https://slurm.schedmd.com/sbatch.html

申请资源选项

在上述案例中, 无论是 srun, salloc 还是 sbatch 都默认你申请一个计算节点, 启动一个进程, 不使用GPU, 并有默认的运行时长上限. 如果你想要申请更多资源 (比如你需要使用GPU, 就必须加上GPU选项!), 或者指定一些运行设定, 都可以添加选项.

比如, 加 -t 30 表示申请运行30分钟的任务, 就直接把选项加在命令后面:

srun -t 30 python3 helloworld.py
salloc -t 30
sbatch -t 30 test.sh

请注意,选项必须紧跟 SLURM 命令。

  • ❌ 错误示例: sbatch test.sh -t 30
  • ✅ 正确示例: sbatch -t 30 test.sh

对于 sbatch, 还可以把选项放在脚本的开头, 以 #SBATCH 开头, 而且必须接在 #!/bin/bash 的后面, 放在所有的命令前面, 否则就会被当成普通的注释. 比如:

#!/bin/bash
#SBATCH -t 30
pwd; hostname; date
echo "Running python on the server"
python3 helloworld.py

下面介绍一些其它常用选项. 长选项和短选项都是可用的, 短选项备注在括号中 (若存在).

选项 默认值 描述
--time=<walltime> (-t <walltime>) 6 小时 运行任务的时间限制, 格式如下 [hours:]minutes[:seconds] 如 20, 01:20, 01:20:30 days-hours[:minutes][:seconds] 如 2-0, 1-5:20, 1-5:20:30
--cpus-per-task=<number> (-c <number>) 1 每个任务所能使用的线程数、(逻辑)核数. 通常需要自己指定
--gres=gpu:[gpu_type:]:<number> 指定要用的 gpu 数量或类型, 如 --gres=gpu:1. 仅 bigMem0, bigMem1 上有 GPU 并有访问控制. GPU的性能详见我们的Benchmark页面
--job-name=<jobname> (-J <jobname>) 命令名 作业的名称, 有助于帮助你记录你正在运行什么作业.
--output=<path>/<file pattern> (-o <path>/<file pattern>) slurm-%j.out (%j = JobID) 指定标准输出文件的路径以及名字.
--error=<path>/<file pattern> (-e <path>/<file pattern>) slurm-%j.out (%j = JobID) 指定错误输出文件的路径以及名字.
--nodes=<number> (-N <number>) 1 所需要分配的计算节点数.
--ntasks=<number> (-n <number>) 1 启动的任务数量, 几乎只有当你运行 MPI 程序时需要修改这个选项.
--nodelist=<node_name_list> (-w <node_name_list>)   指定在哪台机器上运行, 可能的值为 bigMem{0-3}.

资源调度系统不限制各个程序内存的使用量. 但请合理的使用有限的内存资源.

作业的时间限制最长为7天.

你不可以只申请 GPU 而不申请任何 CPU 的使用.

以下哪个说法是正确的?

其他常用命令

  • sinfo: 查看节点空余状态;
  • squeue: 查看作业队列;
  • scancel: 取消作业.

sinfo

官方文档: https://slurm.schedmd.com/sinfo.html

sinfo命令报告分区和节点的状态.

$ sinfo
HOSTNAMES  AVAIL  STATE  CPUS(Avail/Total)  GRES_USED
bigMem0    up     idle   64/64              gpu:tesla_t4:0(IDX:N/A)
bigMem1    up     mix    54/64              gpu:nvidia_a30:2(IDX:0-1)
bigMem2    up     mix    14/128             gpu:0
bigMem3    up     alloc  0/512              gpu:0

上述输出表示有四个计算节点, bigMem0 是 idle 即完全空闲的; bigMem1 是 mix, 表示有一部分核被用户使用了, 且GPU被占用了前两个; bigMem3 显示 alloc, 表示该计算节点的所有核都被占用了, 此时其他用户无法再申请那台机器上的资源.

squeue & scancel

官方文档: https://slurm.schedmd.com/squeue.html, https://slurm.schedmd.com/scancel.html

在等待你的程序执行的同时, 你可以通过 squeue 知道程序的状态. 例如, 在 loginNode 上列出所有正在队列中的作业:

$ squeue

你会看到

JOBID USER    NAME        ST CPUS GPUS END_TIME         NODELIST    REQ_NODES
4902  qsxu    vasp_job    R  48   N/A  2024/09/04 17:43 bigMem[2-3] bigMem3
4898  qsxu    vasp_job    R  48   N/A  2024/09/04 17:29 bigMem[2-3] bigMem3
4897  qsxu    vasp_job    R  48   N/A  2024/09/04 17:29 bigMem[2-3] bigMem3
4896  qsxu    vasp_job    R  48   N/A  2024/09/04 17:29 bigMem[2-3] bigMem3
4793  yjzhang dissociatio R  256  N/A  2024/09/07 01:39 bigMem3     bigMem3
  • JOBID: 作业编号.
  • USER: 提交作业的用户名.
  • NAME: 作业名称.
  • ST: 作业状态. 从提交到完成的典型作业状态是: PENDING (PD) 和 RUNNING (R). 如果你没有看到你的作业, 那么很可能它已经完成了. 此外有时候你能看到的状态是 COMPLETING (CG), 表示作业已完成, 正在结束.
  • CPUS: 作业申请的核数. 你可以通过这一列推断某一个节点上还有多少空闲的核可用.
  • GPUS: 用户申请节点时使用的GPU. 如果为N/A, 表示用户并没有使用.
  • END_TIME: 作业预计结束时间. 如果该作业正在运行中, 这个时间表示该作业最晚可能的结束时间 (注意到所有作业都有运行时长限制, 如果不设置时长, 默认的运行时长是一天; 最多可申请的运行时长是七天.) 如果该作业正在排队中, 这是 slurm 根据当前队伍的长度为你预估的结束时间, 没有任何保障你的任务一定会在这个时间点前结束. 如果显示 N/A, 表明 slurm 暂时未安排你的任务, 无法预估何时结束.
  • NODELIST: 作业所占用的节点.
  • REQ_NODE: 用户申请的节点. 如果为空, 表示用户并没有指定节点.

如果你想中断正在运行的作业或取消排队, 请使用以下命令取消它:

scancel <jobid>

有时, 取消正在运行的作业需要较长的时间 (尤其是 I/O 密集型作业), 此时作业会进入 CG 状态.

scontrol

提交作业后你会得到一个作业号, 以下用 <jobid> 表示. 如果忘了你的作业号, 且你的作业还没有运行结束, 可以通过 squeue 命令查看你的作业编号.

用以下命令查看你提交的作业状态的详细信息:

scontrol show job <jobid>

用以下命令查看节点的状态的详细信息:

scontrol show node <nodename>

例如

$ scontrol show node bigMem0
NodeName=bigMem0 Arch=x86_64 CoresPerSocket=16
   CPUAlloc=28 CPUEfctv=64 CPUTot=64 CPULoad=3.78
   AvailableFeatures=(null)
   ActiveFeatures=(null)
   Gres=gpu:tesla_t4:4(S:0-1)
   NodeAddr=bigMem0 NodeHostName=bigMem0 Version=22.05.2
   OS=Linux 3.10.0-1160.36.2.el7.x86_64 #1 SMP Wed Jul 21 11:57:15 UTC 2021
   RealMemory=1030499 AllocMem=0 FreeMem=717245 Sockets=2 Boards=1
   State=MIXED ThreadsPerCore=2 TmpDisk=0 Weight=1 Owner=N/A MCS_label=N/A
   Partitions=partition
   BootTime=2023-09-11T13:27:35 SlurmdStartTime=2023-11-30T07:26:18
   LastBusyTime=2024-01-30T14:32:36
   CfgTRES=cpu=64,mem=1030499M,billing=64
   AllocTRES=cpu=28
   CapWatts=n/a
   CurrentWatts=0 AveWatts=0
   ExtSensorsJoules=n/s ExtSensorsWatts=0 ExtSensorsTemp=n/s

用以下命令查看系统中的预约信息:

scontrol show reservation

另可参见 SLURM 官方文档对 scontrol 的介绍: https://slurm.schedmd.com/scontrol.html

预约节点资源

预约节点资源就像在饭店里预定座位一样, 你可以预订从某个时间点开始到某个时间点结束, 只有你指定的一部分用户可以使用你指定的一部分节点. 一旦节点被预约, 则其他用户无法提交可能结束时间晚于预约开始时间的作业. 如果你需要预约节点, 请发邮件至管理员邮箱. 邮件内容必须包括:

  1. 预约开始时间 (精确到某一个小时,如北京时间2月1日上午9点) 和预约结束时间 (精确到某一个小时,如北京时间2月4日上午9点). 除非有特殊需求,否则预约时间不得超过七天.
  2. 预约的节点名称, bigMem0, bigMem1, bigMem2 或 bigMem3. 除非有特殊需求,否则预约节点数不得超过一个.
  3. 预约的核数, 如无特殊声明, 默认为预约节点上所有核.
  4. 需要在这段时间内使用节点的用户名称, 用逗号分隔. 如: aduser1, aduser2, aduser3.
  5. 使用节点的具体用途.

预约条件: 预约开始时间必须晚于当前节点正在运行的任务的最终结束时间, 请提前用 squeue 查看节点状态. 此外, 每一个被包含在上述用户列表中的用户每个月有1024核时的额度, 且预约次数不得超过3次. 若超出额度, 则需要提供导师知情且同意的证明.

例:

  • 用户 aduser 申请1月7日9点-21点使用bigMem1:64核, 12小时, 若当前没有任务预计运行到1月7日9点, 则预约成功. 用户 aduser 申请1月14日9点-21点使用bigMem1:64核, 12小时, 预约不成功, 因为超出了该月使用额度.
  • 用户 aduser 申请1月的每个周六使用bigMem1一小时, 管理员只能为她预约前三次, 因为第四次超出了该月使用额度.

发送邮件后, 管理员会及时和你联系, 告知预约是否成功. 预约成功后, 请在预约时间内用 SLURM 提交任务. 如果管理员在24小时内连续两次看到被预约的节点并没有在运行任何任务, 管理员有权取消你的预约. 若多次违约, 管理员有权取消你的预约资格.

接下来干嘛?

阅读 关于服务器储存空间的规则.


Copyright © 2020-2024 Advancedsolver Admin Team.