> For the complete documentation index, see [llms.txt](https://book.ncrnalab.org/teaching/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.ncrnalab.org/teaching/getting-started/cluster.md).

# Run jobs in a cluster \[Advanced]

## 0) Introduction of cluster

我们提供的另一种解决方案是不在本地机器上运行程序，而是登录到安装linux系统远程服务器，在服务器上完成操作。

生物信息学中的很多数据处理任务比日常工作中需要更多的计算能力，所以在实际工作中，计算量比较大的任务我们通常都是在远程服务器上完成的。集群(cluster)是一组相互独立的远程服务器，通过高速的网络组成一个计算机系统。集群对外表现为单一的系统，协同起来向用户提供系统资源和系统服务。

在使用者的角度，集群中的节点可以分为登录节点和计算节点。通常情况下，使用者可以像登录普通linux服务器一样登录到集群的登录节点上，再利用集群上安装的作业管理系统向计算节点提交任务。常见的作业管理系统有[PBS](https://www.openpbs.org) (Portable Batch System), [LSF](https://www.ibm.com/docs/en/spectrum-lsf/10.1.0?topic=overview-lsf-introduction) (loading share facility)和[slurm](https://slurm.schedmd.com/documentation.html)等，不同作业管理系统提交任务的方式有所区别，但是大同小异。

{% hint style="warning" %}
**注意** 用户需要通过作业管理系统向计算节点提交任务，登录节点计算资源非常有限，所以在登录节点一般只是用来进行任务提交和简单的脚本编辑等，**不要**在登录集群后后**直接运行**大的运算任务，否则将直接影响其他用户的正常使用。
{% endhint %}

下面以清华大学生物计算平台用slurm实现作业管理的生物信息计算集群（P/T cluster) 为例，介绍服务器和集群的具体使用。

## 1) 服务器远程登录

* 在不同的操作系统上，我们通常都是利用ssh协议远程登录linux服务器。
* -p后为端口号,默认为22,但是很多服务器出于安全考虑会设成别的值。

```bash
ssh -p portnumber username@166.111.*.*
```

* 输入`exit`回车即可退出登录

**1a) Mac用户：**

从“/Applications⁩/⁨Utilities” 中打开 "Terminal" 软件，用上述命令远程登录。

**1b) Windows用户：**

windows的各种终端，如默认的terminal(按windows+R回车，再输入cmd回车可调出)或powershell(在docker配置部分有介绍)等都可以用于ssh登录。也可以选择其他一些工具，例如:

* [Xshell](https://xshell.en.softonic.com/),选择家庭/学校免费版下载。
* [putty](https://www.putty.org/)
* [FinalShell](http://www.hostbuf.com/)

## 2)文件传输

* 常见的方式有如下两种:

1. ftp/sftp客户端: 开源软件[FileZilla](https://www.filezilla.cn/)是一个比较流行的ftp/sftp客户端。在FileZilla的图形界面输入服务器ip地址和端口号(sftp的端口号和ssh的端口号相同)及用户名密码即可实现远程登录。
2. 命令行工具: `scp`(用于远程的文件复制)和`rsync`(用于远程的文件复制和增量同步/备份等)。

{% hint style="warning" %}
**注意** 在我们的P集群上,`/home`目录存储有限，请大家在`/data`目录下建立自己的目录用于数据存储。
{% endhint %}

## 3) 环境配置

* 如前文所述，学习生物信息分析除了需要在linux环境下进行操作，还需要使用很多前人开发的软件工具。
* 我们在集群上为大家预装了一些需要用到的软件，有些是直接安装在服务器上的，有些是安装在sigularity镜像中。

### 配置环境变量

* 以下脚本将安装在服务器上的工具添加到环境变量`$PATH`中，方便直接调用。所以大家在登录集群后需要先运行这一行命令:

```bash
source /WORK/Samples/singularity.sh
```

* 用`which`命令可以看到目前在`$PATH`环境变量的软件的具体安装位置，例如

```bash
# which singularity
/WORK/app/singularity-2.0-20191204/bin/singularity
# 这表明我们当前使用的sigularity软件安装在/WORK/app/singularity-2.0-20191204/bin目录下
```

### 使用singularity镜像

* [singularity](https://sylabs.io/guides/3.5/user-guide/introduction.html)是和Docker类似的一种容器(container)技术。利用这种技术可以方便的将一台机器的软件环境打包到另外一台机器上运行，这对于配置一些依赖比较复杂的工具非常有用。
* 不同于Docker，使用者在运行在singularity时不需要root权限，所以部署安装应用的时候更加灵活，适合在公共的cluster上提供给非root的用户使用。
* **本机无法配置Docker的同学可以使用cluster上的singularity**。
* 和docker类似，我们可以通过交互式或非交互式的方式来使用singularity镜像。

#### (1) 交互式运行singularity容器

* 进入容器:

```bash
singularity run /data/images/bioinfo_tsinghua.simg
```

* 输入`exit`即可退出容器
* 演示动画如下：

![](/files/-MIcPZ4jxBFv3zNxxpoL)

* singularity和docker一样支持容器和宿主器的文件同步。
* 与docker不同,singularity默认就会把宿主机的家目录`~`挂载到容器的家目录`~`,所以在singularity容器内在家目录进行读写等同于对宿主机的家目录进行读写。
* 如果我们想在singularity容器内部读写`/data`目录下的内容，可以通过如下两种方式实现:

```bash
# 用以下两种方式均可将宿主机的目录/data挂载到容器目/data下，实现二者的文件同步

# method 1:
export SINGULARITY_BINDPATH='/data:/data'
singularity run /data/images/bioinfo_tsinghua.simg

# method 2:
singularity run --bind /data:/data /data/images/bioinfo_tsinghua.simg
```

* singularity的文档对于文件系统的挂载给出了详尽的介绍，如果希望进一步了解请参考<https://sylabs.io/guides/3.1/user-guide/bind_paths_and_mounts.html>。

#### (2) 非交互式运行singularity容器

* 在宿主机直接调用singularity镜像内部安装的软件

```bash
# 这里调用的是容器的echo命令而非宿主机的echo命令
# 实现文件同步的方式和singularity run相同
singularity exec /data/images/bioinfo_tsinghua.simg echo "hello world"
```

## 4) How to use cluster

集群上安装的作业管理系统会通过排队的方式为不同用户提交的任务分配计算资源。

{% hint style="warning" %}
**注意** 重申一下，每个用户需要通过slurm向`CN_BIOT`队列提交计算任务，登录节点计算资源非常有限，**不要**在登录进cluster后**直接运行**大的运算任务，否则将直接影响其他用户的正常使用。
{% endhint %}

### (1) Example 1. submit a mapping job

* 在第一个例子中，我们提交一个用直接安装在服务器上的tophat软件进行reads mapping的任务。

#### (1.1) 准备任务提交脚本 `test1.sh`

我们通过在脚本开头添加以`#SBATCH`开头的几行配置向slurm指定作业提交的相关参数:

```bash
#!/bin/bash
#SBATCH -J tophat_test
#SBATCH -p CN_BIOT
#SBATCH --nodes=1
#SBATCH --ntasks=4
#SBATCH --output=%j.out
#SBATCH --error=%j.err

export PATH=/WORK/teaching/bin:$PATH # using tophat installed in /WORK/teaching/bin
mkdir -p mapping-wt1 # create output directory
tophat --bowtie1 -p 4 -G /WORK/teaching/diff-exp/yeast_annotation.gff --no-coverage-search -o mapping-wt1 /WORK/teaching/diff-exp/bowtie_index/YeastGenome /WORK/teaching/diff-exp/Raw_reads_10k/wt1.fq
```

| Name                    | mean                                          |
| ----------------------- | --------------------------------------------- |
| #SBATCH -J tophat\_test | 命名job name为“tophat\_test”                     |
| #SBATCH -p CN\_BIOT     | 使用CN\_BIOT这个queue(在slurm中被称为partition)        |
| #SBATCH --nodes=1       | 使用一个节点。多数生物信息软件不支持跨节点的并行计算，所以通常会把任务限制在单节点上    |
| #SBATCH --ntasks=4      | task数为4。slurm默认为一个task分配一个核，所以会有4个核分配给当前提交的脚本 |
| #SBATCH --output=%j.out | 运行日志输出到当前目录中，以 .out 结尾                        |
| #SBATCH --error=%j.err  | 运行错误日志输出到当前目录中，以 .err 结尾                      |

#### (1.2) 使用sbatch命令提交 `test1.sh`

```bash
sbatch test1.sh
```

### (2) Alternative ways

我们可以将脚本中指定的参数拿到脚本外面:

```bash
#!/bin/bash
export PATH=/WORK/teaching/bin:$PATH # using tophat installed in /WORK/teaching/bin
mkdir -p mapping-wt1 # create output directory
tophat --bowtie1 -p 4 -G /WORK/teaching/diff-exp/yeast_annotation.gff --no-coverage-search -o mapping-wt1 /WORK/teaching/diff-exp/bowtie_index/YeastGenome /WORK/teaching/diff-exp/Raw_reads_10k/wt1.fq
```

```bash
sbatch -J tophat_test -p CN_BIOT --nodes=1 --ntasks=4 --output=%j.out --error=%j.err test1.sh
```

除此之外，我们还可以利用`--wrap`参数直接提交一个命令，而不一定要将其放在一个脚本中:

```bash
sbatch --output={log.out} --error={log.err} --cpus-per-task=1 --exclude=biot03 --ntasks=4 -p CN_BIOT  --wrap "export PATH=/WORK/teaching/bin:$PATH;tophat --bowtie1 -p 4 -G /WORK/teaching/diff-exp/yeast_annotation.gff --no-coverage-search -o mapping-wt1 /WORK/teaching/diff-exp/bowtie_index/YeastGenome /WORK/teaching/diff-exp/Raw_reads_10k/wt1.fq"
```

### (3) Example 3. submit a RNAediting job

在第二个例子中，我们提交一个用安装在singularity镜像中的工具[RNAeditor](http://rnaeditor.uni-frankfurt.de/)进行RNA编辑分析的任务。 这个工具依赖比较复杂，所以使用singularity是一个比较好的选择。 该例子一共需要准备3个文件，具体见（2.1）-（2.3）。

#### (3.1) RNAeditor配置文件`RNAeditor.config`

```bash
# This file is used to configure the behaviour of RNAeditor

# Standard input files
refGenome = /WORK/teaching/rna_regulation/rnaeditor/data/Homo_sapiens.GRCh38.ch1.fa
gtfFile = /WORK/teaching/rna_regulation/rnaeditor/data/Homo_sapiens.GRCh38.chr1.gtf
dbSNP = /WORK/teaching/rna_regulation/rnaeditor/data/dbSNP.vcf.new
hapmap = /WORK/teaching/rna_regulation/rnaeditor/data/HAPMAP.vcf
omni = /WORK/teaching/rna_regulation/rnaeditor/data/1000GenomeProject.vcf
esp = /WORK/teaching/rna_regulation/rnaeditor/data/ESP.chr1.vcf
aluRegions = /WORK/teaching/rna_regulation/rnaeditor/data/Repeats.chr1.bed
output = /data/{username}/test-RNA-editing/output/chr1
sourceDir = /usr/local/bin/
maxDiff = 0.04
seedDiff = 2
standCall = 0
standEmit = 0
edgeDistance = 3
intronDistance = 5
minPts = 5
eps = 50
paired = False
keepTemp = True
overwrite = False
threads = 5
```

#### (3.2) RNAeditor运行脚本`run-RNAeditor.sh`

* 假设配置文件保存在`/data/{username}/test-RNA-editing`目录下

```bash
#!/bin/bash
export PATH=/apps/RNAEditor/ui:/apps/RNAEditor/ui:/apps/RNAEditor/scripts:/apps/RNAEditor/website:/apps/RNAEditor/ressources:$PATH
mkdir -p /data/{username}/test-RNA-editing/output
RNAEditor.py -i /WORK/teaching/rna_regulation/rnaeditor/chr1.fq -c /data/{username}/test-RNA-editing/RNAeditor.config
```

#### (3.3) 提交任务脚本`submit-RNAeditor.sh`

```bash
#!/bin/bash
#SBATCH -J rnaeditor_test
#SBATCH -p CN_BIOT
#SBATCH --nodes=1
#SBATCH --ntasks=5
#SBATCH --output=%j.out
#SBATCH --error=%j.err

export SINGULARITY_BINDPATH='/WORK,/data' #将/WORK和/data两个目录挂载到singularity容器的同名目录下
singularity exec /WORK/teaching/image/rnaeditor_1.8.simg bash run-RNAeditor.sh #用镜像rnaeditor_1.8.simg运行run-RNAeditor.sh脚本
```

准备好这三个文件后，用`sbatch`提交即可

```bash
sbatch submit-RNAeditor.sh
```

### (4) Monitor and manage jobs

* 查看队列信息

```bash
squeue
```

* 查看特定一个job的信息

```bash
scontrol show job {jobid}
```

* 查看节点信息

```bash
sinfo
```

* 取消任务

```bash
scancel {jobid}
```

### (5) Tips

1. 有的时候个别计算节点会出现故障，但slurm仍会向这些节点分配任务，导致出错。还有的时候我们需要长时间大量的运行任务，又不想把节点全部占用以至于其他同学完全无法使用。这两种情况下我们都可以利用sbatch提供的`--exclude`参数。例如如果biot03和biot04出现了故障，或者我们想把这两个节点留给其他同学，我们可以将提交任务的命令改成:

```bash
sbatch -J foo -p CN_BIOT --nodes=1 --ntasks=4 --exclude='biot03,biot04' --wrap "sleep 10"
```

1. 任务要尽量小而多。可以用bash等脚本的for循环产生多个提交脚本, 然后在用for命令在命令行里一次性的将这些脚本提交;也可以利用前面提到的`--wrap`参数在for循环中直接提交命令。要尽可能把大的任务拆分成小的，建议一次提交的任务数是**总核数的5-10倍**，比如一个集群容许每个用户最多跑50个jobs，那么可以一次提交250-500个jobs的脚本。但是每个脚本的时间要尽可能短（建议每个大约\~10min - 2hour）。
2. 每个节点之间的内存是独立的，绝大多数生物信息学工具没有MPI的支持，这就意味着它们只能同时利用同一个节点上的多个核。所以我们通常都会加上`--nodes=1`参数，将同一个任务的cpu分配限制到一个节点上。
3. 对于大内存软件要注意多分配一些核数。如前所述，绝大多数生物信息学工具没有MPI的支持，因而在计算中无法同时使用多个节点的内存。在1个节点上同时运行多个大内存开销的程序时，容易因为内存不够导致程序异常退出。 例如, 用[STAR](https://github.com/alexdobin/STAR) mapping人类基因组时,一个人类基因组的index大约要占用30G内存。 运行STAR时，推荐为每个mapping的任务分配6个核，这样的话, 如果1个node有128G memory、20 core，一次用6 core，不仅可以加速计算，而且每个任务都可以占用40G以上的内存, 应该不太容易内存溢出了 （如果还是溢出就增加 core=8,10,12...)。

对于P集群，一个node有64G, 16 core, 运行star这样的程序时，我们推荐独占一个node，1个node上运行1-2个程序(`--ntasks`设成8或16)：

```bash
#SBATCH --nodes=1
#SBATCH --ntasks=16
```

## 5) Teaching Videos

* see Videos in the [**Files needed** ](https://courses.ncrnalab.org/files)[ ](/teaching/appendix/appendix-iv.-teaching.md#4-teaching-videos)
