集群任务调度,最初读研究生的时候,接触的是实验室用的condor(https://research.cs.wisc.edu/htcondor/),目前还在维护。在脚本里面设定好请求的计算资源,交给master节点即可,调度系统会自动分配和管理任务。这也是我对集群管理中的任务调度的初始了解。后来不管是工作还是在实验室,遇到最多的是SGE(sun grid engine)。再后来SGE被Oracle抛弃,又接触了Slurm和Torque。不管何种系统,通过集群调度来实现分析的分布式计算,而不用关系具体的任务分配,极大的提高了集群的利用率和分析效率。

关于流程管理,如果只有一两个样本的情况下,我都是直接把pipeline放到sh脚本上直接跑,懒得用流程管理。但如果样本很多,成百上千个样本的时候,最好用流程管理,来追踪大规模任务的分析状态,是否报错,是否成功结束,以免手工check造成遗漏。我有时候会在命令之后加&& touch “Done"或者判断$0的状态,来确保程序正确执行,但这样做确实很繁琐。后来snakemake开始流行,又是和python结合,易读性很好,就尝试开始用snakemake。一个Snakefile文件,可以搞定N多样本,还能监控分析的进度。

正好最近需要在一个slurm调度管理的集群上进行分析,而流程本身就封装在Snakefile文件中,如果体验了snakemake和slurm合体,体验非常好,颠覆了我对向集群投递任务的繁琐印象。要是放在以前,我要分析1000个样本,我可能要生成1000个script,需要专门写一个生成job script的script,然后再投递。我也知道可以通过传参进行批量投递,但体验非常不好。所以还是感慨技术的进步,也推荐snakemake和slurm一起用。本文主要提一下如何微调下资源请求的命令。

假设我的Snakemake文件有1000个job,我需要向集群提交任务,如果和slurm或者SGE配合使用,需要用到–cluster和–jobs选项。

1
2
3
snakemake --cluster "sbatch -N 1 --ntasks=1  --cpus-per-task=10" --jobs 10
# --cluster 后面跟的是提交命令,如果是SGE的话,就是qsub
# --jobs是最大同时投递的任务数目

很多文档中提到要在Snakefile中的每个rule中设置resources,比如resources: mem_mb = 40000,但我发现这样提交的任务,是获取不了具体的请求资源。这个时候用scontrol show job jobid查看请求的资源,可以看到可以用10个cpu,但请求的内存依然是默认的。

查了很多教程,都是通过配置yaml或者json文件,我觉得这样很繁琐,而且每个rule的请求资源是不一样的,通过配置文件,相当于多了一个文件,多了很多工作。看到有人说–cluster中可以用wildcards,就打开了我的思路。比如在rule设置了相对应的内存和时间,可以通过wildcards来调用,不同的rule的任务,提交时就对应不同的资源请求。实现起来是这样的

1
snakemake --cluster "sbatch -N 1--mem={resources.mem_mb} --ntasks=1  --cpus-per-task=10 " --jobs 10

这个时候,可以进一步把snakefile里面的threads信息利用起来

1
snakemake --cluster "sbatch -N 1--mem={resources.mem_mb} --ntasks=1  --cpus-per-task={threads} " --jobs 10

这个时候scontrol show job jobid显示请求资源是我们想要的,但squeque的job名是snakemake.job,分不清现在正在运行的任务对应哪个rule,可以这么修改。

1
snakemake --cluster "sbatch -N 1--mem={resources.mem_mb} --ntasks=1  --cpus-per-task={threads} --job-name={rule}" --jobs 10

那么,进一步让输出日志和错误日志可读,可以这么修改

1
2
3
snakemake --cluster "sbatch -N 1--mem={resources.mem_mb} --ntasks=1  --cpus-per-task={threads} --job-name={rule} --output={rule}.%j.out --error={rule}.%j.err" --jobs 10

snakemake --cluster "sbatch --nodes=1 --exclude=gpu1 --job-name={rule} --mem={resources.mem_mb} --ntasks=1 --cpus-per-task={threads} --output={rule}.%j.out --error={rule}.%j.err" --jobs 15

如果想进一步修改job名的可读性和日志文件的可读性,可以把rule里面的wildcards传进来。比如我的每个rule中都匹配了sample,那在传给 job-name和output, errror的时候,把{wildcards.sample}传过来就行。如果我不想把任务投递给一个node节点,可以通过exclude(比如–exclude=gpu1)来指定。

总结

提交的命令可以参考这个

1
snakemake --cluster "sbatch -N 1--mem={resources.mem_mb} --ntasks=1  --cpus-per-task={threads} --job-name={rule} --output={rule}.%j.out --error={rule}.%j.err" --jobs 10

snakemake是神器,推荐。

参考

https://accio.github.io/programming/2020/06/16/Snakemake-with-slurm.html

EMBL的snakemake和slurm结合使用:https://www.embl.org/groups/bioinformatics-rome/blog/2022/04/snakemake-profile-4-defining-resources-and-threads/

sbatch命令手册: https://slurm.schedmd.com/sbatch.html

https://hackmd.io/@bluegenes/BJPrrj7WB

配置一个cluster_config.yml或者json格式文件,提交的时候指定–cluster-config cluster_config.yml,还可以配置不同的rule和default rule。

https://bluegenes.github.io/snakemake-via-slurm/

####################################################################

#版权所有 转载请告知 版权归作者所有 如有侵权 一经发现 必将追究其法律责任

#Author: Jason

#####################################################################