[关闭]
@Yalei-SONG 2018-12-22T05:54:38.000000Z 字数 10087 阅读 4085

SLURM使用指南

我们用新购置的服务器搭建了一个集群。与使用多台服务器不同,使用集群时,我们会感觉就像在使用一台计算机一样。使用以前的服务器时,我们需要登录到每台服务器来提交任务,在集群上提交任务时,方法略有不同。
我们使用SLURM来进行资源管理和任务调度。如果你此时对我们的集群和SLURM完全陌生,希望接下来的内容能够帮助你顺利地查看集群的状态、提交任务、管理任务。

ssh: 如何登录集群?

集群由1台登录节点(master)和8台计算节点(node[1-8])组成。一般只允许用户从登录节点登录,并且任务的提交、查询、终止等操作也只能在登录节点上进行。

登录节点目前只开放了ssh登录。Linux用户可以直接使用ssh和scp命令,Windows用户可以使用PuTTYWinSCP等工具,务必从官网下载。

请牢记,不要使用登录节点执行计算任务!

sinfo: 如何查看节点的状态?

所有与计算有关的任务都要通过SLURM进行调度。SLURM包含了很多命令,我们用这些命令来查询、提交、管理我们的任务。srun就是我们第一个遇到的命令。
在登录集群(即master)之后,提交任务前需要先看一下集群中各个计算节点的状态,可以用sinfo命令来简单地查看各个节点的状态,如下所示:

  1. [zhangsan@master ~]$ sinfo
  2. PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
  3. ptt1 up infinite 1 mix node2
  4. ptt1 up infinite 1 alloc node1
  5. ptt2* up infinite 5 mix node[3-7]
  6. ptt2* up infinite 1 idle node8

输出内容分别显示了分区、可用情况、时间限制、节点数目、状态、节点列表信息。
sinfo默认会将相同状态的节点合并显示,比如第三行,就是将node3、node4、node5、node6、node7的状态合并显示。
在SLURM中,常会用到方括号来表示数字列表。比如这里[3-7]表示3,4,5,6,7,有时也会遇到[3-5,7]的形式,表示3,4,5,7。

我们的集群包含8个计算节点,即node[1-8],它们的配置分为两类,因此我们把集群分为两个分区(Partition),即ptt1和ptt2。
ptt1包括node[1-2],每个节点包含144个核心,1TB内存;ptt2包括node[3-8],每个节点包含144个核心,256GB内存。可见两个分区中的节点只是内存不同。提交的每个任务只能选择两个分区中的一个,默认为ptt2。

注意这里的状态(STATE)中,常见的状态有idle,mix,alloc。idle表示此节点为空闲状态,可以提交任务;mix表示此节点正在执行任务,并且还可以接受新的任务;alloc表示此节点正在执行任务,而且已经没有剩余的核心或者没有剩余的内存可被申请。

如果需要查看更详细的信息,可以查阅sinfo的手册,在命令行输入man sinfo即可查阅手册,输入q退出。
推荐添加如下参数来查询更详细的节点信息:

  1. sinfo -N -o "%.6N %.5P %.5a %.11T %.8m %.8e %.8O %.15C"

结果如下所示:

  1. [zhangsan@master ~]$ sinfo -N -o "%.6N %.5P %.5a %.11T %.8m %.8e %.8O %.15C"
  2. NODELIST PARTI AVAIL STATE MEMORY FREE_MEM CPU_LOAD CPUS(A/I/O/T)
  3. node1 ptt1 up mixed 1031213 836489 89.25 114/30/0/144
  4. node2 ptt1 up mixed 1031213 859542 72.34 112/32/0/144
  5. node3 ptt2* up allocated 257117 142698 83.26 144/0/0/144
  6. node4 ptt2* up allocated 257117 114452 83.59 144/0/0/144
  7. node5 ptt2* up allocated 257117 180319 94.22 144/0/0/144
  8. node6 ptt2* up allocated 257117 165675 123.70 144/0/0/144
  9. node7 ptt2* up allocated 257117 89056 103.52 144/0/0/144
  10. node8 ptt2* up allocated 257117 134824 109.94 144/0/0/144

这里列出了各个节点更加详细的信息,总内存(MEMORY),可用内存(FREE_MEM),CPU负载(CPU_LO),各结点可用核心情况(占用/空闲/其它/总量)。可以根据查询结果和自己的资源需求来决定使用哪些节点来执行计算任务。

如何估计程序需要的资源?

核心

单线程程序,只需要申请1个核心。
对于使用C、FORTRAN等语言编译出的程序,一般为单线程,如果使用了OpenMP,可以根据需要申请。
对于MATLAB程序,由于可以自动并行,最多可以将申请的资源全部利用,在提交时一定要声明需要的核心数。需要特别注意的是,对于MATLAB程序,并非线程越多效率越高,而且有时也未必可以将申请的资源全部利用,所以申请过多的资源会造成极大的浪费。

内存

内存占用量,主要取决于程序中申请的变量,和一些对大尺寸变量操作的函数。请查阅在你所用的语言中各变量类型所占的位数(bits),并统计程序中出现的变量以及对较大尺寸变量进行操作的函数。
我们每天会对前一天的资源利用情况进行统计,包含了真实的CPU、内存使用量,请参照实际的使用情况,及时调整你的申请。

srun: 如何提交任务?

在演示提交任务前,我们先了解一下linux中的一个命令,hostname。

  1. [zhangsan@master ~]$ hostname
  2. master.cluster

在命令行界面直接输入hostname,可以将主机名打印到屏幕。如前所述,我们登录到集群上,实际是登录到了登录节点(master)上,所以这里打印出来的结果为master.cluster,其中master为主机名,cluster为域名,master.cluster表示这台机器叫做master,它处在一个名字叫做cluster的域中,这个域中也可能会有其他计算机,比如我们这里还有node[1-8]。

简单地提交单个任务,可以使用srun命令。比如我想提交一个非常简单的任务,hostname:

  1. [zhangsan@master ~]$ srun hostname
  2. node4.cluster
  3. [zhangsan@master ~]$ srun hostname
  4. node6.cluster

这里执行了两次hostname,结果不同,第一次为node4.cluster,第二次为node6.cluster。可见,这里srun自动帮我们分配了执行hostname这一任务的节点,第一次分配了node4,第二次分配了node6。

srun也可以使用-p指定执行任务的分区,比如:

  1. [zhangsan@master ~]$ srun -p ptt1 hostname
  2. node1.cluster

srun也可以使用-w指定执行任务的节点,比如:

  1. [zhangsan@master ~]$ srun -w node5 hostname
  2. node5.cluster

注意,默认分区为ptt2,所以如果没有指定分区的话,相当于自动加上了-p ptt2这一选项。

  1. [zhangsan@master ~]$ srun -w node1 hostname
  2. srun: error: Unable to allocate resources: Requested node configuration is not available

在这里我们指定了node1,但由于没有指定分区,默认分配到ptt2,而node1属于ptt1,所以无法提交。

hostname非常简单,它不需要占用很多资源就可以告诉我们它是在哪台机器上运行的,srun分配了1个核心和1MB内存给它,这也是在不指明需要的资源时的默认配置。但是我们一般的计算任务需要很多计算资源:多个核心,多于1MB的内存。这里仍然以hostname为例:

  1. [zhangsan@master ~]$ srun -p ptt1 -w node1 --mem=5M -c 2 hostname
  2. node1.cluster

这里--mem=5M表示申请5MB内存,-c 2表示申请2个核心。
当然,这里并不能看出hostname在申请到了5MB内存和2个核心之后有什么变化,输出的结果告诉我们hostname已经在node1上执行了。但这是一个非常完整的例子,指明了分区、节点、内存、核心数。注意,声明内存要用长参数,mem前有两个减号,后面还有一个等号,申请的内存的值写法为10M,1G等。

hostname瞬间就可以返回结果,但是假如想执行一个花费时间很长的任务,我们不希望坐在显示器前等着它完成,这时可以在命令的最后使用&符号,将任务放到后台运行,我们可以继续在命令行界面下做别的事。
这里我们以脚本test_touch_for为例,它的作用是每隔10秒便将主机名和当前时间打印到屏幕,打印10次后终止:

  1. [zhangsan@master test_touch]$ srun -p ptt1 -w node1 --mem=5M -c 2 ./test_touch_for &
  2. [1] 60799
  3. [zhangsan@master test_touch]$ node1.cluster
  4. Tue Nov 20 23:23:30 CST 2018
  5. node1.cluster
  6. Tue Nov 20 23:23:40 CST 2018
  7. ls
  8. readme test_touch_for
  9. [zhangsan@master test_touch]$ node1.cluster
  10. Tue Nov 20 23:23:50 CST 2018
  11. node1.cluster
  12. Tue Nov 20 23:24:00 CST 2018
  13. node1.cluster
  14. Tue Nov 20 23:24:10 CST 2018
  15. node1.cluster
  16. Tue Nov 20 23:24:20 CST 2018
  17. node1.cluster
  18. Tue Nov 20 23:24:30 CST 2018
  19. node1.cluster
  20. Tue Nov 20 23:24:40 CST 2018
  21. node1.cluster
  22. Tue Nov 20 23:24:50 CST 2018
  23. node1.cluster
  24. Tue Nov 20 23:25:00 CST 2018
  25. [1]+ Done srun -p ptt1 -w node1 --mem=5M -c 2 ./test_touch_for

在第7行,执行了ls命令,可以将当前路径的文件列出,这表明,在脚本test_touch_for没有执行完时,我们仍可以执行其他命令。注意在第2行,在提交任务后,由于将任务放到了后台,系统会告诉我们PID是60799,这是在master下执行srun的PID,可以在master下用top查看,而不是计算结点node1上执行脚本test_touch_for的PID,但稍后我们可以查询脚本test_touch_for对应的jobID。[1]表示这是我们放到后台的第1个任务。

这里由于脚本会向屏幕输出一些信息,干扰我们的操作,可以使用>重定向,也就是将输入或者输出的位置,由标准输入位置(键盘)、标准输出位置(屏幕),重新指向到其他位置。

  1. [zhangsan@master test_touch]$ srun -p ptt1 -w node1 --mem=5M -c 2 ./test_touch_for 1>log 2>err &
  2. [1] 66610
  3. [zhangsan@master test_touch]$ ll
  4. total 16
  5. -rw-r--r--. 1 root root 0 Nov 21 02:02 22-57-26
  6. -rw-rw-r--. 1 zhangsan zhangsan 0 Nov 21 02:00 err
  7. -rw-rw-r--. 1 zhangsan zhangsan 430 Nov 21 02:02 log
  8. -rw-rw-r--. 1 zhangsan zhangsan 32 Oct 29 21:31 readme
  9. -rwxrwxr-x. 1 zhangsan zhangsan 84 Nov 20 23:07 test_touch
  10. -rwxrwxr-x. 1 zhangsan zhangsan 71 Nov 20 23:23 test_touch_for
  11. [zhangsan@master test_touch]$ cat log
  12. node1.cluster
  13. Wed 21 Nov 02:00:35 CST 2018
  14. node1.cluster
  15. Wed 21 Nov 02:00:45 CST 2018
  16. node1.cluster
  17. Wed 21 Nov 02:00:55 CST 2018
  18. node1.cluster
  19. Wed 21 Nov 02:01:05 CST 2018
  20. node1.cluster
  21. Wed 21 Nov 02:01:15 CST 2018
  22. node1.cluster
  23. Wed 21 Nov 02:01:25 CST 2018
  24. node1.cluster
  25. Wed 21 Nov 02:01:35 CST 2018
  26. node1.cluster
  27. Wed 21 Nov 02:01:45 CST 2018
  28. node1.cluster
  29. Wed 21 Nov 02:01:55 CST 2018
  30. node1.cluster
  31. Wed 21 Nov 02:02:05 CST 2018

其中1>log表示将标准输出写入到文件log中,linux系统多数时候不会依赖后缀名来判断文件类型,使用windows系统的同学可以写入到文件log.txt中,2>err表示将错误输出写入到文件err中。
这里用ll显示当前路径的文件及详细信息,err文件大小为0,即没有错误输出。
任务完成后,可以查看log的内容。
如果显示以下错误输出:

  1. srun: job 3243 queued and waiting for resources

这表示暂时没有满足要求的节点可以执行你的任务,需要排队。

用上述命令提交任务,如果在运行程序的过程中,关掉了终端,有可能会导任务终止,建议此时在命令前添加nohup,即:

  1. nohup srun -p ptt1 -w node1 --mem=5M -c 2 ./test_touch_for 1>log 2>err &

由上述例子可以看出,在master上提交任务时,当前目录是可以传递给计算节点的,提交脚本时可以使用相对路径。

由于各个节点共享存储,各个节点读写的是同一套家目录。因此,同时运行多个任务时,注意彼此之间读写文件的冲突。建议多个任务用不同的日志文件。

特别提醒MATLAB用户:集群上的MATLAB没有图形界面;注意MATLAB命令搜索的顺序;执行脚本时不要加后缀名。

提交MATLAB任务举例:
执行当前路径下的main.m脚本

  1. nohup srun -p ptt2 -w node6 --mem=500M -c 4 matlab -r 'main' 1>log 2>err &

squeue: 如何查询已提交的任务的状态?

提交上任务之后,无论是任务已经开始执行了,还是在排队,都要使用squeue命令及时查询它的状态,尤其是记录它的JOBID。JOBID是SLURM对任务的编号,是SLURM对任务操作时的标识。

  1. [zhangsan@master test_touch]$ squeue
  2. JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
  3. 3235 ptt2 matlab luyixuan PD 0:00 1 (Resources)
  4. 3238 ptt2 matlab luyixuan PD 0:00 1 (Priority)
  5. 3239 ptt2 matlab luyixuan PD 0:00 1 (Priority)
  6. 1387 ptt2 matlab songminy R 4-06:42:33 1 node7
  7. 1771 ptt2 paired_b yaoyuxia R 3-06:29:16 1 node8
  8. 1853 ptt2 matlab chenzhen R 1-14:55:44 1 node7
  9. 1854 ptt2 matlab chenzhen R 1-14:53:47 1 node8
  10. 2921 ptt2 a6 zhangyij R 7:59:08 1 node7
  11. 2922 ptt2 a6 zhangyij R 7:49:52 1 node4

输入squeue即可直接查询到简单的任务信息,JOBID、分区、任务名、用户、状态、已运行时间、占用节点数、节点列表(原因),默认输出所有用户的任务。如果在提交任务后执行squeue,一般底部(执行)或顶部(排队)为其状态,请务必记录其JOBID。
其中常见的状态有排队中(PD),运行中(R)。
前几行往往是正在排队的任务。这里任务3235排队的原因为Resources,即当前剩余资源不能满足任务要求;任务3238和3239排队的原因为Priority,即优先级不如3235高。
如果不想输出所有用户的信息,可以用-u选项:

  1. squeue -u zhangsan

推荐使用squeue时指定输出格式如下:

  1. [zhangsan@master ~]$ squeue -o "%.5i %.10u %.2t %.10M %.6D %.4C %.7m %R"
  2. JOBID USER ST TIME NODES CPUS MIN_MEM NODELIST(REASON)
  3. 844 zhuzhigang PD 0:00 1 1 1M (Resources)
  4. 526 chenzhenqi R 5-09:30:48 1 20 20G node2
  5. 527 chenzhenqi R 5-09:29:35 1 20 20G node2
  6. 529 chenzhenqi R 5-06:06:42 1 100 300G node1
  7. 718 luyixuan R 2-19:37:25 1 2 800M node6
  8. 719 luyixuan R 2-19:37:18 1 2 800M node6
  9. 720 luyixuan R 2-19:35:59 1 2 800M node6
  10. 757 yaoyuxiang R 23:34:38 1 20 20G node7
  11. 781 chenxianzh R 10:39:52 1 2 2G node1
  12. 782 chenxianzh R 10:39:43 1 2 2G node1
  13. 783 chenxianzh R 10:39:35 1 2 2G node1
  14. 784 chenxianzh R 10:39:28 1 2 2G node1
  15. 811 yaoyuxiang R 7:21:53 1 20 20G node3
  16. 815 yaoyuxiang R 7:04:27 1 20 30G node5
  17. 820 yaoyuxiang R 6:31:53 1 20 30G node4
  18. 824 chenxianzh R 5:07:57 1 2 2G node3

这里CPUS和MIN_MEM两列可以显示各个任务的申请的核心数和内存。

sstat: 如何查询已运行的任务的信息?

对于已运行的任务,可以使用sstat来查看更详细的信息,具体方法参见其手册。这里举一个例子。
目前很多同学的任务被终止,原因多数为内存申请得偏小。在任务运行时,监测其使用的内存,对于调整此任务的内存申请很有帮助。

  1. [zhangsan@master ~]$ sstat --format=JobID,AveRSS,MaxRSS -j 3241
  2. JobID AveRSS MaxRSS
  3. ------------ ---------- ----------
  4. 3241.0 437092K 437092K

这里使用sstat来查询任务3241即时使用的物理内存情况。
SLURM中的任务可以由多个任务步组成,对于使用srun提交的任务,一般只有1个任务步。sstat针对每个任务中的任务步来监测,3241.0表示任务3241的第0个任务步。

sattach: 如何与任务进行交互?

可以使用sattach与已经提交的任务进行交互,即把任务的标准输入输出位置指向当前终端,查看其输出,或者输入字符。

  1. [zhangsan@master test_touch]$ srun ./test_touch_for 1>log 2>err &
  2. [1] 113014
  3. [zhangsan@master test_touch]$ squeue -u zhangsan
  4. 3246 ptt2 test_tou zhangsan R 1:08 1 node3
  5. [zhangsan@master test_touch]$ sattach 3246.0
  6. node3.cluster
  7. Wed 21 Nov 03:09:00 CST 2018
  8. node3.cluster
  9. Wed 21 Nov 03:09:10 CST 2018
  10. node3.cluster
  11. Wed 21 Nov 03:09:20 CST 2018
  12. node3.cluster
  13. Wed 21 Nov 03:09:30 CST 2018
  14. ^C

这里执行了三个命令,第一个用srun提交了任务,第二个使用squeue查询zhangsan的任务信息,根据查询到的JOBID,第三条命令使用sattach把当前终端附着到任务步3246.0上,即可看到其输出。可以使用Ctrl+c退出。
这样看来,也可以利用sattach交互式使用MATLAB,但是仍然推荐使用前面提到的重定向至日志文件,这样在发生错误时可以迅速排查错误原因,方便调试,而且可以同时使用sattach。

scancel: 如何取消任务?

如果需要取消任务,可以使用scancel命令。

  1. [zhangsan@master test_touch]$ srun ./test_touch_for 1>log 2>err &
  2. [1] 115977
  3. [zhangsan@master test_touch]$ squeue -u zhangsan
  4. JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
  5. 3248 ptt2 test_tou zhangsa R 0:09 1 node4
  6. [zhangsan@master test_touch]$ scancel 3248
  7. [zhangsan@master test_touch]$
  8. [1]+ Exit 143 srun ./test_touch_for > log 2> err
  9. [zhangsan@master test_touch]$ squeue -u zhangsan
  10. JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)

sacct: 任务结束后需要做些什么?

每个任务结束后,与之相关的信息都会被保存到数据库中,可以通过sacct命令来查看。
若任务顺利执行完毕,则可以用sacct来查询其实际运行过程中使用的内存信息,而当提交的任务运行失败时,也可以用sacct来查询其推出代码(ExitCode),若为9,则为实际使用内存超过了申请的内存。

例如查询20778号任务的信息:

  1. [zhangsan@master ~]$ sacct -ojobid,jobname,partition,alloccpus,state,reqmem,averss,maxrss,exitcode -j 20778
  2. JobID JobName Partition AllocCPUS State ReqMem AveRSS MaxRSS ExitCode
  3. ------------ ---------- ---------- ---------- ---------- ---------- ---------- ---------- --------
  4. 20778 matlab ptt2 2 FAILED 2Gn 23433144K 23433144K 0:9

可以看到此任务申请了2G内存,但实际使用了大约20G内存。

如何获取更多帮助?

希望在阅读上面的内容后,你可以在SLURM环境下提交、管理你的任务了。如果学有余力,可以看一下scontrol,sacct以及sbatch这三个命令的手册。

以前集群调度普遍使用PBS系统,PBS是功能最为齐全,历史最悠久,支持最广泛的本地集群调度器之一。 PBS的包括openPBS,PBS Pro和Torque三个主要分支。其中OpenPBS是最早的PBS系统,目前已经没有太多后续开发,PBS pro是PBS的商业版本,功能最为丰富,Torque,现已被adaptive公司收购,其旧版本功能单一,且发现有很多漏洞,所以我们采用了SLURM系统。

目前中文的SLURM资料非常少,英文资料也仅限于SLURM官网,大家在遇到不懂的问题,或者想进一步研究SLURM的用法时,首先考虑命令对应的手册,其次是官网,但要注意官网中的帮助针对的版本,不同版本间差异较大。

下面是三份中文资料,由简至详:

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注