scnet超算互联网平台使用笔记

scnet 平台和 slurm 调度系统的使用笔记。

简单使用

登录后,点击首页的控制行,然后在这个页面中的顶部有两个重点使用的,如下

  • 文件管理:查看、上传、下载文件
  • 命令行 : 打开一个命令行脚本,这是登录节点,可以运行一些简单的 linux 命令

现在我一进入服务器,第一步就是设置环境,如下

1
2
3
module purge
conda activate zhouziwen
bin=~/zhouziwen/bin

提交作业

分析需要使用 SLURM 调度系统,作业(job)就是是你在超算上从“申请资源”到“跑完程序”的整个任务过程

SLURM 是全球超算界的“普通话”,就像 Linux 系统里的 lscd命令一样,它是一个通用的、开源的作业调度系统。你学到的 SLURM 知识(sbatch, squeue等),换到国内外绝大多数超算中心(如清华、科大、天河二号、阿里云等)都能直接通用。

scnet 官网命令行专区:https://www.scnet.cn/help/docs/mainsite/hpc/cmd/

slurm官网:https://slurm.schedmd.com/

什么是作业?

作业 = Slurm 调度和管理的最小单位

换个说法

  • 你提交一次 sbatch
  • 👉 Slurm 创建一个作业
  • 👉 给它分配 CPU / 内存 / 时间
  • 👉 负责启动、监控、结束

二、没有数组时:1 次 sbatch = 1 个作业

1
sbatch job.sh
1
2
Job 12345
└── 运行 job.sh

三、有数组时:1 次 sbatch = 多个作业

1
#SBATCH --array=1-3
1
2
3
4
Job 12345
├── Job 12345_1
├── Job 12345_2
└── Job 12345_3

四、为什么叫「作业」而不叫「命令」?

作业(Job)

  • ✅ Slurm 管理的
  • ✅ 有资源限制
  • ✅ 有开始 / 结束
  • ✅ 可以单独重跑

命令(Command)

  • ❌ 只是脚本里的一行
  • ❌ Slurm 看不见

创建作业脚本

使用 SLURM 调度系统 ,你需要创建一个作业脚本,标准的叫法是 Batch Job Script(批处理作业脚本),通常直接简称为 Job Script

这个脚本在超算中扮演着**“中介”**的角色,它负责把你(用户)的需求翻译成 SLURM(调度器)能听懂的语言。它的作用可以拆解为两部分:

  1. 上半部分 (#SBATCH ...):“资源订单” (Order) ,这部分以 #SBATCH开头,不是给 Linux 执行的命令,而是给 SLURM 调度器看的“采购单”

    作用:SLURM 读取这些指令后,会去资源池里帮你锁定对应的计算节点、CPU 和内存。如果资源不够,你的作业就会在队列(Queue)里等待。

  2. 下半部分 (Shell 命令):“操作说明书” (Recipe) ,这部分是标准的 Linux Bash 命令,是作业在计算节点上被批准运行后,真正执行的步骤

    作用:告诉计算节点,资源到位后,具体要加载什么软件、激活什么环境、运行什么程序。

运行程序,需要使用提交任务的脚本,相应的脚本示例如下,命名为c.slurm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
#SBATCH -J zhouziwen # 作业的名称 可根据需要自行命名
#SBATCH -p xhacnormalb # 在指定分区中分配资源,根据所拥有的资源修改
#SBATCH --ntasks=1 # 整个作业只分配 1 个 task(任务/进程)
#SBATCH --cpus-per-task=1 # CPU核心数目,变量 $SLURM_CPUS_PER_TASK

export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK # OpenMP 的线程数目

module purge
set -euo pipefail

echo "[INFO] Job started at $(date)"
echo "[INFO] Using $SLURM_CPUS_PER_TASK CPUs"

# 分析内容

echo "[INFO] Job finished at $(date)"

对于脚本内容,下面会有进一步的解释。

提交脚本

提交作业。

1
sbatch run.sh

查看作业运行状态,R就表示作业在运行当中。

1
squeue

运行结束之后会在当前目录生成slurm-xxx.out,其中作业xxx为作业号。这是标准输出文件。

取消作业:先通过squeue查看JOBID,假如JOBID为27532270,使用命令scancel JOBID取消作业。

1
scancel 27532270

目前常用的查询命令

1
2
3
4
5
job_id=21695205

squeue -j $job_id
seff $job_id
tail slurm-${job_id}.out

作业脚本内容解释

常用#SBATCH 参数

完整的参数说明见官网:https://slurm.schedmd.com/sbatch.html

🚀 一、 作业基础信息(名字、队列、时间)

这些是每个脚本的“门面”,用来告诉调度器你是谁,要在哪跑,要跑多久。

参数 (全写) 缩写 说明 示例
--job-name -J 作业名称。起个好记的名字,方便在队列里一眼找到你的任务。 #SBATCH -J my_gwas_analysis
--partition -p 指定分区(队列)。不同分区可能对应不同的硬件(如 CPU/GPU)或权限。 #SBATCH -p cpu_partition
--time -t 最大运行时间。超时会被系统强行杀死!格式可以是 分钟小时:分钟:秒 #SBATCH -t 24:00:00 (24小时)
--account -A 计费账号。多用户或多项目集群必填,告诉系统把算力费算在谁的头上。 #SBATCH -A proj_2024_abc

💻 二、 核心资源申请(CPU、内存、节点)

这是最容易算错的地方,直接关系到你的任务能不能跑起来,或者会不会浪费资源。

参数 (全写) 缩写 说明 示例
--nodes -N 申请的节点数量。单机多核程序设为 1 即可。 #SBATCH -N 1
--ntasks -n 总任务数 (MPI进程数)。通常单节点单进程设为 1。 #SBATCH -n 1
--ntasks-per-node (无) 每个节点的任务数。配合 -N 使用,控制节点内的任务分布。 #SBATCH --ntasks-per-node=4
--cpus-per-task -c 每个任务分配的 CPU 核心数。针对多线程程序(如 Python/OpenMP)。 #SBATCH -c 8
--mem (无) 单节点总内存限制。单位可用 K/M/G/T。优先级高于 --mem-per-cpu #SBATCH --mem=64G
--mem-per-cpu (无) 每 CPU 核心的内存。总内存 = 核心数 × 该值。 #SBATCH --mem-per-cpu=4G

💡 避坑指南:CPU 和内存的分配逻辑
实际总 CPU 核心数 = 节点数(-N) × 每节点任务数(--ntasks-per-node) × 每任务核心数(-c)
申请内存时,--mem 是直接划定节点总内存,而 --mem-per-cpu 是弹性计算。 一般建议直接用 --mem 更直观不易错。


📂 三、 输入输出与日志管理

跑大规模作业时,好的日志习惯能救你一命。

参数 (全写) 缩写 说明 示例
--output -o 标准输出日志文件。支持变量替换,%j 会自动变成 Job ID。 #SBATCH -o logs/job_%j.out
--error -e 标准错误日志文件。如果不设,默认会和 output 合并。 #SBATCH -e logs/job_%j.err
--chdir -D 工作目录。脚本在哪个路径下执行。默认是当前提交目录。 #SBATCH -D /home/user/project/

🎫 四、 特殊硬件与高级控制

当你需要 GPU,或者想要更精细地控制作业流转时使用。

参数 (全写) 缩写 说明 示例
--gres (无) 申请通用资源(如 GPU、高速本地盘)。格式:资源类型:数量 #SBATCH --gres=gpu:1 (申请1块GPU)
--exclude -x 黑名单节点。遇到过某台机器坏了或性能差,可以直接避开。 #SBATCH -x node05,node06
--nodelist -w 白名单节点。强制指定在某几台机器上跑(通常和 --exclusive 连用)。 #SBATCH -w node01
--exclusive (无) 独占节点。哪怕你只用 1 个核,整个节点的 128 核都归你,别人不能用。 #SBATCH --exclusive

作业环境变量

名称 含义 类型 示例
SLURM_JOB_ID 作业id,即作业调度系统为作业分配的作业号,可用于bjobs等命令 数值 hostfile=" ma.$SLURM_JOB_ID" 使用$SLURM_JOB_ID定义machinefile,指定mpi节点文件
SLURM_JOB_NAME 作业名称,即-J 选项指定的名称 字符串 mkdir ${SLURM_JOB_NAME} 根据作业名称创建临时工作目录
SLURM_JOB_NUM_NODES 作业分配到的节点总数 数值 echo $SLURM_JOB_NUM_NODES
SLURM_JOB_NODELIST 作业被分配到的节点列表 字符串 echo $SLURM_JOB_NODELIST
SLURM_JOB_PARTITION 作业被分配到的队列名 字符串 echo $SLURM_JOB_PARTITION

实战组合公式(直接抄作业)

根据不同的业务场景,你可以直接套用以下模板:

  1. 常规单节点多线程任务 (如 Python/R/Shapeit4)
1
2
3
4
5
6
7
8
9
#SBATCH -J my_thread_job
#SBATCH -p normal
#SBATCH -N 1
#SBATCH -n 1
#SBATCH -c 16 # 申请16个CPU核心
#SBATCH --mem=32G # 申请32G内存
#SBATCH -t 12:00:00
#SBATCH -o %j.out
#SBATCH -e %j.err
  1. 纯 MPI 多节点并行任务
1
2
3
4
5
6
7
#SBATCH -J my_mpi_job
#SBATCH -p mpi_partition
#SBATCH -N 2 # 跨2个节点
#SBATCH -n 32 # 总共32个MPI进程
#SBATCH --ntasks-per-node=16 # 每个节点跑16个进程
#SBATCH --mem-per-cpu=2G
#SBATCH -t 48:00:00
  1. GPU 作业 (如深度学习训练)
1
2
3
4
5
6
7
#SBATCH -J my_gpu_job
#SBATCH -p gpu
#SBATCH -N 1
#SBATCH -n 1
#SBATCH --gres=gpu:2 # 关键:申请2块GPU
#SBATCH --mem=128G
#SBATCH -t 72:00:00

指定作业名称

给这个作业起一个名称,完整写法如下:

1
#SBATCH --job-name=hello_world

用处是方便管理,squeue 命令输出的NAME 列显示的就是 -J指定的名字

申请节点数目

申请节点数目通常是1(#SBATCH -N 1)。

在 SLURM 里,Node(节点)= 一台独立的物理服务器(一台机器,有 CPU、内存、硬盘)。

举例如下:

现实世界 SLURM 世界
工厂 超算集群
车间 Partition(分区)
一台机器 Node(节点)
机器里的工人 CPU Core(CPU 核心)

这里作业名称好理解,,使用的核心数目根据具体情况修改(#SBATCH --ntasks-per-node=4)。

什么时候节点大于1

只有 MPI 并行程序才需要多节点

例如:

  • OpenMPI / Intel MPI
  • 自写 C/C++ MPI 程序
  • 某些旧版物理 / 化学模拟软件

什么时候用 MPI 呢?

场景:任务太大,单机内存装不下,或者算 100 年都算不完。

  • 例子:模拟宇宙演化、预测全球气候、训练超大语言模型。
  • 效果:用 100 台机器跑 MPI,可能把 100 年的任务缩短到 1 年。这是 MPI 的绝对主场。

每个节点的任务数(非必须)

#SBATCH --ntasks-per-node=1

这里的“任务”(tasks)指的是独立的程序进程,不是 CPU 核心。一般就是说你准备同时跑几个程序,最常见的用途是**“并行跑多个互不干扰的独立任务”**(通常称为“任务阵列”或“多实例运行”)。举个例子,假如你要同时跑4条命令(没看懂,好像是多进程需要用 srun 启动,这是 slurm 的一个命令,就是在作业中启动 task )。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#SBATCH -p xhacnormalb01
#SBATCH -N 1
#SBATCH --ntasks-per-node=4
#SBATCH -c 2
#SBATCH -J multi_input

module load anaconda3/2023.03
conda activate shapeit4_env

# 同一个脚本,4 个不同输入文件
srun -n 1 -c 2 python my_script.py input1.txt &
srun -n 1 -c 2 python my_script.py input2.txt &
srun -n 1 -c 2 python my_script.py input3.txt &
srun -n 1 -c 2 python my_script.py input4.txt &
wait

如果你只有一个独立任务,可以不设置这个参数,默认就是1个任务。

进一步解释

假设你有 2 行运行 2 个 python 脚本,task=1 和 task=2 有什么区别?

在 Slurm 里,task ≠ 脚本行数,而是一个并行执行单元。正常 task 设为1,表示这个作业只能同时运行 1 个进程

✅ 情况 1:--ntasks=1

1
2
3
#SBATCH --ntasks=1
python a.py
python b.py

实际执行方式:

1
2
python a.py   ← 先跑
python b.py ← a.py 跑完再跑

✔️ 串行执行

✔️ 同一时间只用 1 个 CPU

✔️ 不会违反 Slurm 的资源限制

这是 scnet 上最常见、最安全的写法

❌ 情况 2:--ntasks=2(但你没告诉 Slurm)

1
2
3
#SBATCH --ntasks=2
python a.py
python b.py

⚠️ 这是“隐形违规”

原因:

  • Slurm 以为你有 2 个 task
  • 但你并没有用 srun/ MPI / 并行机制
  • 实际还是 串行 shell 命令

👉 结果:

  • 可能被调度器警告
  • 或浪费资源
  • 或被管理员盯上

什么时候才“真正需要”多个 task?

✅ 正确用法 1:MPI 程序

1
2
#SBATCH --ntasks=16
srun mpirun my_mpi_program

✅ 正确用法 2:srun 并行计算

1
2
3
4
#SBATCH --ntasks=2
srun -n 1 python a.py &
srun -n 1 python b.py &
wait

✅ 正确用法 3:某些古老 Fortran / C 程序(非线程安全)(貌似是说有些80–90 年代写的脚本没有多线程概念,必须使用独立进程)

指定每个任务的CPU核心数目(非必须)

#SBATCH --cpus-per-task=8

这条指令的意思是:告诉 SLURM,每一个“任务(Task)”需要独占 8 个 CPU 核心(Cores)。

如果你有4个任务,那么你就需要 4✖8=32个CPU核心,否则你的作业会排队(Pending),直到有机器能满足这个需求。

当你的程序支持“多线程” 的时候,你就必须要使用这个参数。这是告诉 SLURM:“请给我 8 个核心,我会在这个程序里自己开 8 个线程。”

比如:

  • Python 的 multiprocessing.Pool(8)
  • Java 程序 (-Xmx+ 多线程)
  • R 的 parallel包
  • shapeit4 / impute5 等生信工具(通常自带多线程)

scnet 上的逻辑

收费标准:scnet 上的收费逻辑就是按照你申请的 CPU 数目(#SBATCH --cpus-per-task=8)乘以运行时间。

指定CPU数目的逻辑:使用#SBATCH --cpus-per-task=8申请了8个cpu核心(单节点单任务),平台上就给锁死了8个核心给这个作业使用。就是不管我实际用了几核,这8核始终是为我预留的,别人无法使用。

指定分区

要解释的就是 #SBATCH -p xahcnormal ,这句话是告诉 SLURM :请把我的作业提交到名为 xahcnormal的分区(也叫队列, Partition)中去运行。

完整命令是

1
#SBATCH --partition=xahcnormal

分区是超算里的“不同排队通道”,在 SCNET(以及绝大多数使用 SLURM 的超算)中,计算资源通常被划分为多个 Partition,每个分区有不同的规则:

分区类型 特点 适用场景
normal / xahcnormal 常规计算资源,稳定 普通数据分析、脚本运行
gpu 带 GPU 卡 深度学习、GPU 加速
debug / test 短作业、快速测试 调试代码
highmem 大内存节点 大数据、基因组组装

你这里的 xahcnormal很可能是 SCNET 上的一个“普通 CPU 计算队列”

如何确认你该用哪个分区?在 SCNET 登录节点上执行下面命令,用来实时查看超算集群里“有哪些分区、哪些节点、能不能用”(只会显示你当前账号有权限使用的分区

1
sinfo

你会看到类似这样的表格:

1
2
3
4
5
PARTITION     AVAIL   TIMELIMIT   NODES   STATE    NODELIST
xahcnormal up infinite 8 idle cn[1-8]
xahcnormal up infinite 2 alloc cn9,cn10
gpu up 2-00:00:00 2 idle gpu[1-2]
debug* up 01:00:00 1 drain debug1

我们来逐列拆解它的“黑话”:

列名 (PARTITION) 含义 你的决策参考
PARTITION 队列/分区名(如 xahcnormal 你提交脚本时 -p参数填什么
AVAIL 队列状态 up=可用;down=不可用
TIMELIMIT 最大运行时间 infinite=无限制;01:00:00=限1小时
NODES 节点数量 该队列总共有多少台机器
STATE 节点状态(最关键) 决定了你的作业能否立即运行
NODELIST 具体节点名 哪几台机器处于这个状态

重点关注:STATE(状态)的含义

这是 sinfo里最需要看懂的列,它直接告诉你现在能不能算

状态 (STATE) 含义 能不能提交作业?
idle 空闲(机器闲着,等活干) 最佳时机,提交后秒跑
alloc 已占用(正在运行作业) ⚠️ 可提交,但需排队等待
mix 部分占用(节点还有空位) ✅ 通常可提交(抢占剩余资源)
drain / down 下线/故障(节点坏了) 绝对别提交,会报错
comp 正在释放资源(作业刚结束) ⚠️ 稍等片刻,即将变 idle

SCNET 实战判断

  • 如果你看到 xahcnormal队列有 idle 节点,说明资源充足,你的作业会立刻开始。
  • 如果全是 alloc,说明大家都在排队,你的作业会进入 PENDING状态。

指定内存

SLURM 的内存管理逻辑其实非常“直球”:你申请多少,它就给你锁死多少;你超用了,它就杀进程(OOM Kill)。不存在“按需动态分配”的机制。以下是通用的核心规则,适用于包括 SCNET 在内的大多数集群。

申请规则:不设参数 = 独占整节点

这是 SLURM 最容易被误解的默认行为,也是你在超算上必须显式设置内存的根本原因。

申请方式 计算公式(总内存) 调度器行为 建议场景
不设置 --mem 节点物理内存总量 独占整节点。即使你只跑一个小任务,调度器也会把整个节点的内存划给你,导致资源浪费且排队变慢。 强烈不推荐(除非你是管理员在跑独占测试)。
--mem=10G 10 GB(每节点) 申请固定的总内存池,由该节点上的所有任务共享。 最常用。适合单任务或单节点多任务。
--mem-per-cpu=4G 4 GB × 核心数 (-n) 按核心数分配。申请 4 核就是 16G,申请 8 核就是 32G。 适合 MPI 或 Embarrassingly Parallel 任务。
--mem-per-gpu=8G 8 GB × GPU 数 按 GPU 卡数分配显存对应的主机内存。 适合 GPU 任务。

关键提醒--mem--mem-per-cpu--mem-per-gpu三者互斥,只能选一个写在脚本里。

极少数集群管理员可能会设置 DefMemPerNode=2000(约 2GB)或 DefMemPerCPU=1024(1GB/核),但这不是通用规则。你不能依赖这种“好心”配置。

验证命令:想知道你所在集群的真实配置,可以运行:

1
scontrol show config | grep -A5 -B5 DefMem

我这里输出结果,设置了一个CPU最多 3832MB/1024 约等于 3.74 G (我看运行脚本时也不能超过这个设置,因此当你必须要用高内存时,你要基于内存数目来设置CPU数目,比如 50GB ,就是 50/3.8 = 13.37,因此需要设为 14 )

1
DefMemPerCPU            = 3832

这个好像不准,scnet 平台是每个队列的限额不一样,使用下面的命令查看队列的配置信息,会出来一堆信息,查看 DefMemPerCPU 得到每个 CPU 默认分配 3931 MB 内存,约等于 3.84 GB / 核(按3.8算就行)

1
scontrol show partition xhacnormalb

最后的信息如下

1
2
3
4
5
6
7
PriorityJobFactor=1 PriorityTier=6000 RootOnly=NO ReqResv=NO OverSubscribe=NO
OverTimeLimit=NONE PreemptMode=OFF
State=UP TotalCPUs=37248 TotalNodes=291 SelectTypeParameters=NONE
JobDefaults=(null)
SuspendKeepIdle=n/a
DefMemPerCPU=3931 MaxMemPerNode=UNLIMITED
TRES=cpu=37248,mem=149428500M,node=291,billing=37248

换了一个核存比大一倍的队列 xhacnormalb01,其限额是 7963 MB,也几乎是大了一倍。

问了客服,在 scnet 中,内存是不用指定的,就是根据你指定的 CPU 核心数目确定的,核心越多,内存越大。

module

module是超算用来“切换软件环境”的工具。如果使用自己的 conda 环境,则不用配置。

module load= 把某个软件“拿出来用”。

module purge= 把桌子上所有软件“清空”,重新开始。

在超算上:

  • 有很多不同版本的软件(GCC 7、GCC 9、GCC 12…)
  • 不同软件之间互相打架
  • 所以超算用 module来管理它们

每个 module 就是一个“软件套装”

比如:

  • compiler/gcc/9.3.0= GCC 9.3.0 编译器
  • python/3.10= Python 3.10
  • r/4.5.0= R 4.5.0

它们平时藏在系统里,不主动加载。

常用 module 命令速查表

命令 作用
module avail 看看系统里有哪些软件
module list 看看当前加载了哪些软件
module load xxx 加载某个软件
module purge 清空所有已加载软件
module unload xxx 卸载某个软件

srun

srun 用于提交作业以供执行,或实时启动作业步。一个作业可以包含多个作业步,这些作业步可以在作业分配的节点资源上顺序或并行执行,既可以独占资源,也可以共享资源。

作业步可以用建筑工地比喻

Slurm 概念 现实比喻
Job 一个施工许可证
Job Step 一道工序
srun “开工这道工序”的口令
1
2
3
4
施工许可证(Job)
├── 挖地基(Job Step 0)
├── 搭钢筋(Job Step 1)
└── 浇筑混凝土(Job Step 2)

所有作业步共享这个作业的资源。

常用参数

参数 作用 示例
-n, --ntasks=N 本次 srun 启动 几个 task srun -n 1 python a.py
-c, --cpus-per-task=N 每个 task 用几个 CPU srun -c 4 python a.py
-N, --nodes=N 用几个节点 srun -N 2 ...
--mem=XG 每个 task 的内存 srun --mem=8G

最常用组合如下

1
srun -n 1 -c 1 python a.py

srun单任务并且顺序运行情况下会继承 #SBATCH的所有资源参数。所以一般只有使用 srun并行执行时才需要设置 srun 的参数。

顺序执行

正常下面的写法就是顺序执行,先跑完 a.py ,再跑 b.py

1
2
srun python a.py
srun python b.py

AI 建议一律使用 srun ,相比于不适用 srun 直接跑,好处是

✅ Slurm 知道你在干什么
✅ 资源使用可被监控
✅ 日志、审计、排错更方便

举个例子

假设你的脚本里有 3 个步骤,每个步骤都需要 8 个 CPU 核心(多进程/多线程):

❌ 不推荐的写法(虽然能跑,但有隐患)

1
2
3
4
5
6
7
8
9
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8

# 步骤1:用8核
python step1.py
# 步骤2:用8核
python step2.py
# 步骤3:用8核
python step3.py

隐患:

  1. 监控盲区:Slurm 只看得到你申请了 8 个核,但不知道是哪个进程在用。如果程序内部多线程没生效,你很难排查。
  2. 资源争抢风险:如果某个步骤意外启动了更多线程(比如 Python 的 NumPy 默认会吃满所有 CPU),Slurm 无法限制它,可能导致节点负载过高,被管理员警告。

推荐的写法(清晰、安全)

1
2
3
4
5
6
7
8
9
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8

# 步骤1:明确声明使用8核
srun -n 1 -c 8 python step1.py
# 步骤2:明确声明使用8核
srun -n 1 -c 8 python step2.py
# 步骤3:明确声明使用8核
srun -n 1 -c 8 python step3.py

这里 srun 的参数可以省略(**单节点、单任务、顺序执行、所有srun均没有写-n-c**的情况,下面这种就是经典例子)

1
2
3
4
5
6
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8

srun python step1.py
srun python step2.py
srun python step3.py

不然你就需要完整地写出 srun-n-c 参数(不继承 #SBATCH 的参数)。

好处:

  1. 资源隔离:Slurm 明确知道每一步占用了 8 个核 (程序 被强制绑定到 8 个 CPU 核心 ;即使程序想多用,操作系统也不让用;少用了可能会造成浪费)。
  2. 便于审计sacctsqueue能看到每个 srun步骤的资源消耗。
  3. 符合规范:这是 HPC 集群的最佳实践

具体解释一下好处

**在你这个例子中:写不写 srun **

  • 功能上:几乎没区别
  • 稳定性上:几乎没区别
  • 主要差别在于:可维护性、可观测性、防坑能力

👉 一句话:
srun 在这里不是“为了让它跑”,而是“为了让它更好管”。


二、具体差异对比(这才是你想要的)

假设你现在用的是:

1
2
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8

对比表(写 vs 不写 srun

维度 不写 srun srun
资源申请 继承 Slurm 明确由 Slurm 接管
sacct 可见性 只看到一个 Job Step 能看到 step1 / step2 / step3
出错定位 只知道脚本崩了 知道哪一步崩了
以后改成并行 要重写 只改一行
防误操作

三、最直观的例子:出错时差在哪?

❌ 不写 srun

1
2
3
python step1.py
python step2.py
python step3.py

假设 step2.py 内存爆了。

sacct 看到的是:

1
2
JobID    State   ExitCode
21718711 FAILED 1:0

👉 你只知道:作业挂了
👉 不知道是哪一步


✅ 写 srun

1
2
3
srun python step1.py
srun python step2.py
srun python step3.py

Slurm 内部看到的真实结构如下

1
2
3
4
5
6
7
Job (JobID = 21718711)
├── Job Step 0 (21718711.0)
│ └── python step1.py
├── Job Step 1 (21718711.1)
│ └── python step2.py
└── Job Step 2 (21718711.2)
└── python step3.py

sacct 看到的是:

1
2
3
4
5
JobID       State   ExitCode
21718711 FAILED 1:0
21718711.0 COMPLETED 0:0
21718711.1 FAILED 1:0 ← step2 炸了
21718711.2 CANCELLED 0:0

👉 一眼定位 step2
👉 极大提升排错效率

一句话总结(重点)

srun 不是为了“跑得动”

是为了“看得见、改得动、死得起”

每个作业步还可以单独取消

1
scancel 21718711.1

并行执行

这里必须设置好 ntask ,例如

1
#SBATCH --ntasks=2

或者

1
#SBATCH --ntasks-per-node=2

常用的方式就是后台执行,然后必须加 wait(wait的作用是等待所有后台进程结束,再继续执行脚本。不加 wait,脚本会在“把任务扔到后台”之后立刻结束,Slurm 会认为作业已经完成,于是把还没跑完的后台任务全部杀掉。),示例如下(此时 srun 必须设置 -n ,也就是任务数,)

这里不用 srun 限定死进程和CPU核心数,直接跑python脚本的话很容易CPU核心数超出限制。

1
2
3
4
5
6
7
8
#!/bin/bash
#SBATCH -p xhacnormalb
#SBATCH --ntasks=2
#SBATCH --cpus-per-task=1

srun -n 1 -c 1 python a.py &
srun -n 1 -c 1 python b.py &
wait

这里 srun 必须写全 -n-c 选型(AI 说 srun 不自动继承 --cpus-per-task 或者继承不完整)。

但是 slurm 不建议用 srun 并行计算。建议首先使用 slurm 数组并行计算。

因为这是在一个作业内部并行,会形成一个大作业,占用的CPU和内存资源多,容易导致排队的时间长。而且整个脚本的运行时间时最慢的子任务的时间,这样计费的时候也没有下面slurm数组并行计算划算,因为 slurm 数组并行计算是拆分成多个子作业,每个子作业之间互不干扰单独计费。

使用 slurm 数组并行计算

除了 srun 可以并行运算,slurm 更建议使用的是slurm 数组进行并行计算。

Slurm 数组(Job Array)= 一次性提交一批“结构相同、输入不同”的作业,针对同一个脚本,同一个 sbatch 命令的操作的情况。

好处是容易拓展到 10/100 个任务。

写法举例

脚本必须要“消费”这个编号,举例如下(使用 slurm 数组也建议使用 srun

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
#SBATCH -p xhacnormalb
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=1
#SBATCH --array=0-1
#SBATCH -J gwas_array

module purge
module load anaconda3/2023.03
conda activate shapeit4_env

python my_script.py input_${SLURM_ARRAY_TASK_ID}.txt

当数组很大时(任务很多,比如100个),建议如下设置(% 号后面是最大并发数,这里表示最多同时跑10个,剩下90个排队)

1
#SBATCH --array=1-100%10

这里输入文件格式为

1
2
input_0.txt
input_1.txt

如果脚本不用这个编号,举例如下

1
2
3
#SBATCH --array=0-1

python my_script.py input.txt

结果就是重复运行了2个相同的作业,一般来说没有意义

作业 实际运行
job_0 python my_script.py input.txt
job_1 python my_script.py input.txt

创建数组

下面命令创建数组(语法是 --array=起始值-结束值闭区间,只要 起始值 ≤ 结束值,并且都是非负整数即可,一般起始值是0或1)

1
#SBATCH --array=0-1

Slurm 会自动提交:

作业 SLURM_ARRAY_TASK_ID
job_0 0
job_1 1

创建数组还支持离散值

1
#SBATCH --array=1,3,5,7
作业 SLURM_ARRAY_TASK_ID
job_1 1
job_3 3
job_5 5
job_7 7

运行逻辑

创建数组时:1 次 sbatch 会创建多个子作业(12345_1 等),每个子作业都是一个完整的作业,都有自己的生命周期(Slurm 调度器会根据空闲CPU的数目,每个子作业需要多少资源,用户的最大并发作业数限制来自动判断能同时跑多少子作业,跑不完的就排队)。

1
#SBATCH --array=1-3
1
2
3
4
Job 12345
├── Job 12345_1
├── Job 12345_2
└── Job 12345_3

slurm 数组会给每个子作业一个 SLURM_ARRAY_TASK_ID,子作业的 job ID 就是根据主作业的 job ID 加上 SLURM_ARRAY_TASK_ID 确定的。

1
#SBATCH --array=1-3
子作业 SLURM_ARRAY_TASK_ID
Job 12345_1 1
Job 12345_2 2
Job 12345_3 3

这里主作业是一个“容器 / 管理器”,真正干活的是子作业(array tasks)。主作业的作用是定义数组,通过#SBATCH 统一资源规格,作为 scancel / squeue 的入口 ,举例如下,取消主作业会取消所有子作业。

1
scancel 12345   # 取消所有子作业

三、用例子把这件事彻底讲清楚

每个数组任务(子作业)都会独立执行一遍整个 sbatch 脚本(除了 #SBATCH 行),不同子作业的区别只在于 SLURM_ARRAY_TASK_ID不同 (因此脚本中必须要用到这个 ID ,不然不同子作业就完全一样了) 。

举例脚本如下,这里 #SBATCH 属于主作业,但是效果作用在每一个子作业上 ,因此可以说其实是给子作业设置的,也是所有子作业共享的。这里ntasks=1 始终设为为1,因为子作业的 ntasks 是1,因此设置 ntasks=1 (除非你的子作业内部是 MPI 并行脚本,那么此时 ntasks 就按照子作业的任务数目来设置)

1
2
3
4
5
6
7
8
#!/bin/bash
#SBATCH --array=1-2
#SBATCH --ntasks=1

echo "Job start: $SLURM_ARRAY_TASK_ID"
python step1.py input_${SLURM_ARRAY_TASK_ID}.txt
python step2.py input_${SLURM_ARRAY_TASK_ID}.txt
echo "Job end: $SLURM_ARRAY_TASK_ID"

2️⃣ Slurm 实际做了什么?

作业 1

1
2
3
4
Job start: 1
python step1.py input_1.txt
python step2.py input_1.txt
Job end: 1

作业 2

1
2
3
4
Job start: 2
python step1.py input_2.txt
python step2.py input_2.txt
Job end: 2

两个作业并行
每个作业内部是顺序执行
脚本可以有很多行

slurm 数据的正文命令也同样推荐使用 srun 生成作业步,方便报错的时候排查以及查看每一步的资源调用情况,完整版代码如下。

Slurm 数组并行计算脚本中,srun的继承规则和普通顺序运行脚本完全一样 (下面语句也是单任务顺序运行的情况,因此会自动继承 -c 选项)。

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
#SBATCH --array=1-2
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8

echo "Job start: $SLURM_ARRAY_TASK_ID"

srun python step1.py input_${SLURM_ARRAY_TASK_ID}.txt
srun python step2.py input_${SLURM_ARRAY_TASK_ID}.txt

echo "Job end: $SLURM_ARRAY_TASK_ID"

比对 srun 并行与 slurm 数组

维度 srun &+ wait(作业内并行) Slurm 数组(Array Jobs)
并行层级 进程级(在一个作业里打架) 作业级(独立的子作业)
资源隔离 极差(互相抢内存/CPU) 完美(每个子作业独享资源)
独立性 ❌ 一个崩,全挂 ✅ 一个崩,不影响其他
重跑成本 ❌ 必须重跑整个作业 ✅ 只重跑失败的子作业
日志管理 ❌ 混在一起,难排查 ✅ 天然分离,一目了然
调度友好性 ❌ 霸占节点时间长 ✅ 调度器更容易安排
scnet 推荐度 ⭐(不推荐) ⭐⭐⭐⭐⭐(强烈推荐)

为什么不推荐 srun 并行?(深度解析)

你之前给出的那个例子,就是典型的 “反例”

1
2
3
4
5
6
7
8
#SBATCH --ntasks=4
#SBATCH --cpus-per-task=2

srun -n 1 python a.py &
srun -n 1 python b.py &
srun -n 1 python c.py &
srun -n 1 python d.py &
wait

原因:

  1. 资源“内卷”与“饿死”

虽然你申请了 4 个 tasks,但如果 a.py 是个内存黑洞,把节点的内存吃光了,那么 b.pyc.pyd.py 就会因为申请不到内存而卡死。而在 Slurm 数组中,每个子作业都是独立的,互不相干。

  1. 调度器的“误判”

在共享集群(如 scnet)上,管理员设置的策略通常是鼓励短作业小作业

  • srun 并行:你提交了一个大作业,占用 4 个核,跑 10 个小时。
  • 数组:你提交了 10 个小作业,每个占用 1 个核,跑 1 个小时。
    调度器更愿意优先处理你的 10 个小作业(因为它们更容易塞进空闲节点),而那个大作业可能需要排队很久。
  1. 无法“断点续跑”

如果你的作业跑了 9 个小时失败了,用 srun 并行的方式,你必须从头再来,重新跑 10 个小时。
用数组,你只需要找到那个失败的 job_id_12345,单独重跑它,节省 9 个小时。


三、什么时候才应该用 srun 并行?

只有一种情况 必须srun 并行:

你的程序是 MPI 程序,且必须在同一个作业内通信。

例如:

  • 分子动力学模拟(GROMACS, LAMMPS)
  • 计算流体力学(OpenFOAM)
  • 气象模拟

除此之外,95% 的生信分析、数据处理、Python/R 脚本,都应该用 Slurm 数组。


四、你的场景应该怎么选?

结合你之前提到的 Shapeit4 / Python / GWAS

你的任务 推荐方案
100 个样本,分别跑 Shapeit4 Slurm 数组
10 个染色体,分别跑 GWAS Slurm 数组
一个 Python 脚本,内部用多进程加速 单作业 + -c 8(不用数组,也不用 srun 并行)
一个 Python 脚本,调用外部 MPI 库 srun 并行(唯一特例)

单脚本内部多线程 / 多进程

比如 python 脚本采用 multiprocessing包同时处理8个输入文件,那么 slurm 脚本只需要设置 -c 参数即可

1
2
3
4
5
#SBATCH --ntasks=1
#SBATCH --cpus-per-task=8

···
python test.py 8 # 告诉python是8个进程

Slurm 排障最常用的命令

Slurm 命令的统一命名规则为

s + 功能主体 + 动作

命令 本质 一句话记忆
sbatch 提交 submit a batch job
squeue 排队 show job queue
sinfo 系统 Slurm info
scontrol 控制 control Slurm
sstat 统计 job statistics
sacct 记账 Slurm accounting
scancel 取消 cancel job
srun 运行 run job step

1️⃣ squeue

查看当前作业队列(正在跑 / 等待 / 挂起)

1
2
squeue
squeue -j JOBID

可以配合 tail 命令查看日志信息

1
tail slurm-JOBID.out

2️⃣ sacct

查看已完成 / 已结束作业的历史记录(最核心排障命令)

1
sacct -j $job_id --format=JobID,State,ExitCode,MaxRSS,ReqMem,AllocCPUS,Elapsed,TotalCPU  --units=G

--format=... 自定义输出字段,解释如下。--units=G 设置内存单位为 GB 。

字段 含义 为什么放这里
JobID 作业 ID 定位用
State 作业状态 ✅ 第一眼看是否失败
ExitCode 退出码 ✅ 区分 0 / 非 0
MaxRSS 实际最大内存 ✅ 是否 OOM
ReqMem 申请的内存 ✅ 是否申请过多
AllocCPUS 申请的 CPU ✅ CPU 是否浪费
Elapsed 墙上时间 ✅ 跑了多久
TotalCPU CPU 总工作量 ✅ 是否跑满

两个时间的区别如下,TotalCPU ÷ Elapsed ≈ 平均用了几个 CPU 核心

指标 含义 单位
Elapsed 作业从开始到结束的墙上时间 时:分:秒
TotalCPU 所有 CPU 核累计工作时间 天-时:分:秒

输出结果示例如下

1
2
3
4
5
6
7
(zhouziwen) [ach0yyfeio@login04 2026-04-28-林麝GWAS分析]$ sacct -j $job_id --format=JobID,State,ExitCode,MaxRSS,ReqMem,AllocCPUS,Elapsed,TotalCPU  --units=G
JobID State ExitCode MaxRSS ReqMem AllocCPUS Elapsed TotalCPU
---------------- ---------- -------- ---------- ---------- ---------- ---------- ----------
21695271 FAILED 1:0 19.19G 5 01:00:54 01:00:37
21695271.batch FAILED 1:0 12.86G 5 01:00:54 01:00:37
21695271.extern COMPLETED 0:0 0.00G 5 01:00:54 00:00.003

这里一个作业会出现三个进程,这是 Slurm 为一个作业自动创建的三种不同“作业步骤(Job Steps)”。第一行是主作业,不是具体运行的程序,只是一个抽象对象,只是一个外壳,显示的是汇总信息;第二行 .batch 是脚本真正执行的地方,实际看这一行;第三行是 slurm 的辅助进程,可以忽略。

  • State常见: COMPLETED(完成)、FAILED(失败)、CANCELLED(被取消)
  • ExitCode 退出码 0:0 正常
  • MaxRSS可看内存使用峰值,这里可以看到最大使用内存 12.86G,小于设定的上限 19.19G
  • TotalCPU ÷ Elapsed ≈ 平均用了几个 CPU 核心 ,这里可以看到应该是只用了1个CPU,存在CPU浪费,但是为了使用内存,没有办法。

seff

seff的全称通常是 Slurm Efficiency(Slurm 效率计算工具)。它是 SACCT 命令的一个封装,能够以更直观、易读的格式展示作业完成后的资源消耗和利用率。

主要功能:

  • 复盘历史作业:查看已经运行结束的作业实际消耗了多少资源。
  • 评估资源申请合理性:帮助你判断之前申请的 CPU、内存和时间是否合理。

它的语法非常简单,直接跟上作业 ID 即可:

1
seff [JobID]

举例如下

1
2
3
4
5
6
7
8
9
10
11
12
$ seff $job_id
Job ID: 21718711
Cluster: xhcs3
User/Group: ach0yyfeio/ach0yyfeio
State: COMPLETED (exit code 0)
Nodes: 1
Cores per node: 5
CPU Utilized: 00:56:49
CPU Efficiency: 20.07% of 04:43:05 core-walltime
Job Wall-clock time: 00:56:37
Memory Utilized: 15.53 GB
Memory Efficiency: 80.92% of 19.19 GB

前面的信息不说了,就解释后面的 CPU 和 内存部分

资源类型 指标 数值 利用率 分析与评价
CPU 申请配置 1 节点,每节点 5 20.07% 严重不足 申请了 5 核,但实际只用了约 1 核。 剩余 4 核全程空转,造成资源浪费。
实际消耗 00:56:49 (CPU 时间) 这是所有CPU实际干活的时间
理论应耗 04:43:05 (Core-Walltime) 就是下面的钟表时间乘以CPU核心数目
内存 申请配置 19.19 GB 80.92% 非常优秀 内存申请量与实际需求量非常接近,几乎没有浪费。
实际消耗 15.53 GB 该作业在运行过程中,达到过的“峰值内存(Maximum Resident Set Size)
时间 实际运行 00:56:37 (墙上时钟) - 作业从开始到结束共耗时约 57 分钟。

3️⃣ sinfo

查看分区/节点状态(只会显示当前账号可使用的分区信息)

1
2
3
sinfo # 查看分区状态
sinfo -p xhacnormalb
sinfo -n a02r01n02

示例结果如下

1
2
3
4
5
6
7
8
$ sinfo -p xhacnormalb
PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
xhacnormalb up 333-08:00: 2 drng a02r04n03,a04r05n05
xhacnormalb up 333-08:00: 1 drain a02r08n06
xhacnormalb up 333-08:00: 51 mix a01r01n[01,04,06],a01r02n[04-06],a01r03n[05,07-08],a01r04n06,a01r05n01,a01r06n01,a01r08n08,a02r01n02,a02r02n[01,06-08],a02r03n07,a02r04n04,a02r05n02,a02r07n[04-06],a02r08n03,a03r01n08,a03r04n06,a03r06n07,a03r07n06,a03r08n[01,04-05],a04r01n[01,03],a04r02n08,a04r03n01,a04r06n[04-05],a04r08n03,a06r01n02,a06r03n01,a06r04n[03-05],a06r05n01,f13r[01,10,18],g05r[04-06]
xhacnormalb up 333-08:00: 213 alloc a01r01n[02-03,07-08],a01r02n[01-03,07-08],a01r03n[01-04,06],a01r04n[01-05,07],a01r05n[02-08],a01r06n[02-07],a01r07n[01-08],a01r08n[01,03-07],a02r01n[05-08],a02r02n[02-05],a02r03n[01-03,06,08],a02r04n[01-02,05-08],a02r05n[01,03-08],a02r06n[01-08],a02r07n[01-03,07-08],a02r08n[01-02,04-05,07-08],a03r01n[01-07],a03r02n[01-04,08],a03r03n[01,04-05],a03r04n[01-05,07-08],a03r05n[01-04,08],a03r06n[01,03-06,08],a03r07n[01-05,07-08],a03r08n[02,06-08],a04r01n02,a04r02n[06-07],a04r03n[02-04,06-08],a04r04n[01-08],a04r05n06,a04r06n[01-03,06-08],a04r07n[01-08],a04r08n[01-02,04-08],a06r01n[01,05-08],a06r02n[01,03,05-07],a06r03n[02-06],a06r04n[06,08],a06r05n[03-04,06,08],a06r06n04,f13r[02-07,11-13,15-16],f14r[02,04],g05r[01,07-08]
xhacnormalb up 333-08:00: 24 idle a01r08n02,a02r01n03,a02r03n[04-05],a03r02n[05-07],a03r03n[06-08],a03r05n[05-07],a03r06n02,a03r08n03,a04r05n[01-03,07-08],a06r01n[03-04],f13r17,f14r01

各字段解释如下

字段 含义
PARTITION 分区名(队列名)
AVAIL 分区是否可用(up表示正常,其他表示分区不可用)
TIMELIMIT 该分区最大作业运行时间
NODES 符合该行状态的节点数量
STATE 节点状态
NODELIST 具体节点名

常用节点状态如下,能用的就是 idle/ mix

状态 含义
IDLE 节点完全空闲,可接受新作业
MIX 节点部分被占用,仍有剩余资源
ALLOC 节点资源已全部分配,不能接新作业
DOWN 节点不可用(故障/网络/配置等)
DRAIN 节点不再接受新作业(但已有作业可跑完)
DRNG 正在变成 DRAIN(draining)
FAIL 节点被认为失效,通常伴随 DOWN
MAINT 维护状态(常见在一些集群定制中)
RESV 节点被预留(Reservation)占用
UNKNOWN slurmctld 暂时不知道节点状态

4️⃣ scontrol show job JOBID

查看作业的详细运行参数(更加实时和底层,一般用不到,除非前面都没有找到问题)

1
scontrol show job JOBID

✅ 使用场景:

  • 实际申请了几核/几内存
  • 绑到哪些节点
  • 环境变量、工作目录、限制参数

5️⃣ scontrol show node NODENAME

查看节点详情(管理员/排障常用),用不上

1
scontrol show node node01

✅ 使用场景:

  • 节点为什么 drain/down
  • 内存/CPU 实际可用多少
  • 正在跑哪些 job

6️⃣ scancel

取消/终止作业

1
2
3
scancel JOBID
scancel -u $USER # 清楚该用户的所有作业
scancel -t PENDING # 只取消“等待中(PENDING)”的作业

✅ 使用场景:

  • 提交错了
  • 死锁/卡死
  • 批量清队列

7️⃣ sstat -j JOBID

sstat 是从 Slurm 的 作业步(step)运行时状态 里,实时读取 当前资源使用情况 的工具。注意,只要脚本中没有使用 srun ,不管你这个 slurm 脚本顺序运行了多少个子脚本,它们始终就是一个作业步 (step),sstat 统计的始终是整个脚本的资源总和,无法区分单个子脚本吃了多少内存/CPU。

查看运行中的作业资源使用

1
2
sstat -j 21689846
sstat -j 21689846 --format=JobID,MaxRSS,AveRSS,MaxCPU,AveCPU

对我没用,输出结果一直是空的,因为我没有用 srun 来拉起子任务,Slurm 就认为不需要像监控 MPI 任务那样高频地刷新每个进程的详细状态给 sstat,所以 sstat觉得没东西可报。

常见字段如下

类别 字段示例 含义
CPU AveCPU, MaxCPU 平均 / 最大 CPU 使用时间
内存 AveRSS, MaxRSS 平均 / 最大内存使用
进程 AveVMSize, MaxVMSize 虚拟内存
IO AveDiskRead, AveDiskWrite 磁盘读写
任务 NTasks 任务数
Step StepID 作业步(如 batch, extern

🧭 排障“标准套路”(实战顺序)

1
2
3
4
5
6
squeue -u $USER
sacct -j JOBID
scontrol show job JOBID
tail slurm-JOBID.out
sinfo
sstat -j JOBID

📌 一句话总结

squeue(在哪)→ sacct(为什么)→ scontrol(细节)→ log(报错)→ sinfo(资源)

这 5 条能解决 90% 的 Slurm 问题。

我一般使用的命令行如下

1
2
3
4
5
job_id=21695205

squeue -j $job_id
sacct -j $job_id --format=JobID,State,ExitCode,MaxRSS,ReqMem,AllocCPUS,Elapsed,TotalCPU --units=G
tail slurm-${job_id}.out

mobaxterm连接超算

官方说明:https://www.scnet.cn/help/docs/mainsite/hpc/cmd/connect-to-hpc/

在官方的命令行窗口中,点击上方选项框中的SSH连接,里面有主机-端口号-用户名,还需要下载密钥。

然后在 moba 中新建 SSH ,在下面的 “Advanced SSH settings” 点击 “Use private key” ,然后选中下载的密钥文件。然后正常填写主机-用户名-端口即可。

复制命令出现 0~ 1~

在 MobaXterm 里出现 0~1~前缀,不是软件的行号功能,而是终端“括号粘贴模式(Bracketed Paste Mode)”不兼容导致的转义字符乱码。这与 SecureCRT 的机制完全不同,无需在 GUI 里找设置,直接在终端里关闭即可。

这是 Shell 环境(如 bash)与终端模拟器握手失败导致的。远程的 Shell 开启了“括号粘贴模式”,但 MobaXterm 的终端模拟器未能正确解析该信号,导致将控制字符显示成了可见的 0~1~

解决方案(二选一)

方案 A:临时解决(立即生效)

在当前打开的 ScNet 终端窗口中执行以下命令,关闭该模式:

1
printf "\e[?2004l"

执行后,在当前窗口再次粘贴,乱码前缀就会消失 。

方案 B:永久解决(推荐)

为了避免每次登录都要输入命令,请将配置写入 ScNet 服务器上你的个人配置文件中。

  1. 登录 ScNet,编辑你的 Shell 配置文件(通常是 ~/.bashrc):

    1
    nano ~/.bashrc
  2. 在文件末尾添加一行:

    1
    bind 'set enable-bracketed-paste off'

    或者(如果上一条无效):

    1
    printf "\e[?2004l"
  3. 保存并退出(Ctrl+X-> Y-> Enter)。

  4. 让配置生效:

    1
    source ~/.bashrc

    或者直接断开重连 SSH 会话 。

为什么不用找 GUI 设置?

MobaXterm 的 Settings -> Configuration -> Terminal 里确实有粘贴相关的选项(如 Paste using right-click),但那是控制本地行为的(如是否允许右键粘贴),无法解决远程 Shell 发来的控制序列乱码问题

总结:直接在 ScNet 的终端里执行一次 printf "\e[?2004l"即可立即解决,或者修改 ~/.bashrc一劳永逸。

报错提示Network error: Software caused connection abort

mobaxterm 偶尔出现下面的报错,自动退出,但是

你遇到的这个错误:

Network error: Software caused connection abort

MobaXterm 在连接 SCNET 平台时,SSH 会话被服务器端或中间网络设备主动断开 导致的。而你提到 WinSCP 正常,说明:

✅ 网络本身是通的

✅ 服务器没挂

✅ 账号密码/密钥没问题

❌ 问题出在 MobaXterm 的 SSH 会话保持机制服务器端超时设置


原因

这种现象(MobaXterm 偶尔断开,但 WinSCP 正常)的根本原因是 SSH 协议的工作机制服务器/网络的空闲超时策略 之间的冲突。

简单来说:服务器或中间的防火墙认为你“死了”,把你踢掉了,而 MobaXterm 没有及时“打招呼”告诉服务器它还在。

以下是详细的技术原因分解:

  1. SSH 连接是“无状态”的(相对于 HTTP)
  • 当你用 MobaXterm 连接 SSH 时,建立的是一个长连接
  • 一旦连接建立,除非你主动操作,否则客户端和服务器之间平时不会频繁交换数据
  1. 服务器的“空闲超时”机制 (Idle Timeout)
  • 为了安全和管理资源,大多数 Linux 服务器或高性能计算集群(HPC,如你的 SCNET)的 SSH 服务(sshd)或网络防火墙(Firewall/iptables)都设置了 “空闲超时” 时间。
  • 默认值通常是 5 分钟(300秒)到 15 分钟不等。
  • 规则是: 如果在这个时间段内,没有任何数据包通过这条连接,服务器/防火墙就会认为这个连接“已经废弃”,强行切断它。
  1. MobaXterm vs WinSCP 的行为差异(关键点)
  • MobaXterm (终端模式)
    • 它的主要功能是提供一个交互式 Shell。
    • 如果终端处于“空闲”状态(比如你没敲键盘,或者命令运行完了在等待),MobaXterm 默认不会发送任何数据。
    • 结果:服务器等了 5 分钟没动静,就把它踢了 -> 出现 “Software caused connection abort”
  • WinSCP (文件传输模式)
    • 它的主要功能是传输文件。
    • 如果你打开 WinSCP 但没有在传文件,它其实也在“空闲”。
    • 但是,WinSCP 有一个隐藏的机制:它通常会每隔几分钟自动刷新一下目录列表,或者在后台保持微弱的心跳。
    • 更重要的是,WinSCP 有时使用了不同的 SSH 子系统(SFTP),有些服务器对 SFTP 的超时策略更宽松,或者 WinSCP 的底层库(比如 PuTTY 的 fork)可能默认开启了 Keepalive。
  1. 网络中间设备(NAT / 防火墙)
  • 如果你是在校园网、公司网或者通过跳板机连接 SCNET,中间会经过路由器或防火墙。
  • 这些设备也有一张“连接表”。如果长时间没有流量,它们也会为了节省内存,把这条连接记录删掉。
  • 一旦记录被删,下次 MobaXterm 想发数据时,找不到路了,就会报错“Connection Abort”。

总结

特性 MobaXterm (断开) WinSCP (正常)
状态 空闲(无操作) 空闲(可能有后台刷新)
心跳机制 默认不发送(或间隔太长) 默认可能更频繁 / 使用了不同的底层库
结果 被服务器/防火墙判定为死连接,强制断开 保持活跃,未被断开

所以,解决办法的核心就是:让 MobaXterm 像 WinSCP 一样,即使你不打字,也要定期给服务器发个“我还活着”的信号(Keepalive)。

✅ 解决方案(推荐按顺序尝试)

目前尝试了方法一

✅ 方法一:在 MobaXterm 中设置“保持连接”(最常用有效)

  1. 打开 MobaXterm → 点击顶部菜单 Settings → Configuration
  2. 左侧选 SSH → SSH settings
  3. 勾选:
    • “SSH keepalive”定期(默认通常是 30 秒)向服务器发送一个“空包”(keepalive 包),告诉服务器 “我还活着,别断开我”。)
    • “Fix connection issues”(我这没有,好像也不要紧。这是一个“自动修复”功能,MobaXterm 会尝试在检测到断开后,自动重连 + 恢复终端状态。)
  4. 设置 “Keepalive interval”3060秒(推荐 30,我这也没有)
  5. 点击 OK 保存
  6. 重新连接 SCNET

💡 原理:定期发送空包保持会话活跃,避免被服务器或防火墙踢掉。

方法三:在 MobaXterm 会话中设置“自动重连”

没有下面的选项,所以就没法设置。

  1. 打开你的 SCNET 会话 → 右键 → Edit session
  2. 切换到 SSH → Advanced SSH settings
  3. 勾选:
    • “Auto reconnect”
    • “Reconnect after” 设为 5
  4. 保存

💡 即使断开,MobaXterm 会自动重连,体验更平滑。

🧪 为什么 WinSCP 不断开?

因为 WinSCP 默认使用 SFTP 协议 + 自动重连 + 心跳机制,且它不依赖终端会话的“保持活跃”,而是基于文件系统操作,所以更稳定。

MobaXterm 是 终端模拟器 + 多协议客户端,对 SSH 会话的“保活”更敏感,需要手动配置。

绕过 VPN

我怀疑可能是我用的 VPN 造成的网络不稳定,从而使得网络错误的报错。

没有办法配置,因为 FIClash 会自动更新配置,见下,放弃。但是我看 FIClash 的连接中,scnet 应该就是直接连接的。

下面将scnet 服务器的地址设置为 走物理网卡(直连),不要走 VPN 虚拟网卡。

第一步获得 SCNET 的 IP 地址,复制 WinSCP 登录时填写的 “Host”(主机名),这个 Host 可能是两种情况:

  1. 纯 IP 地址(例如 114.212.xxx.xxx):这就是你需要的服务器 IP。
  2. 域名(例如 login.scnet.edu.cn):如果是域名,你需要先把它转换成对应的 IP 地址 (不需要,直接用域名)。
    • 按下键盘的 Win + R键,输入 cmd回车打开黑色命令行窗口。
    • 输入 ping 你的域名(例如 ping login.scnet.edu.cn)并回车。
    • 系统会自动解析出对应的 IP 地址(显示类似 正在 Ping login.scnet.edu.cn [114.212.xxx.xxx]...),记下这个 IP。

第二步:在 FIClash 中设置“直连”绕过

由于 FIClash 会自动更新配置,因此修改其配置没有用

点击配置,点击那三个点,点击编辑,点击弹出窗口的编辑

rules:列表的最前面(确保在任何代理规则之前),添加一行直连规则:

  • 如果是域名,添加:- DOMAIN,SUFFIX,scnet.cn,DIRECT
  • 如果是 IP,添加:- IP-CIDR,114.212.100.50/32,DIRECT(请确保将 IP 替换为你实际的 SCNet IP)

第三步:验证是否生效

  1. 回到 FIClash 主界面,确保你的代理模式处于 “规则 (Rule)” 模式(非常重要,如果是“全局”模式分流规则是不生效的)。
  2. 打开 WinSCP 尝试连接 SCNet。
  3. 如果之前因为 VPN 导致的卡顿、超时或拒绝连接消失了,顺利弹出了输入密码的窗口(或者直接连上了),就说明绕过成功!

winscp 登录

新建标签页,输入主机-端口-用户名-密码,点击高级设置,在 SSH - 验证 - 密钥文件,选择刚刚下载的文件(这里默认是.ppk,下载的.txt,所以一开始选不上,需要在弹出窗口文件类型那里选择所有文件),然后 winscp 会自动转化生成并选择 .ppk 格式的密钥格式。

然后登录即可。

连接超时

每次登录均弹出下面的提示:

AI 的解释和解决思路:

你遇到的这个弹窗是因为 WinSCP 默认在 15 秒内如果没有收到服务器响应,就会判定超时并弹出警告

在科研计算平台(如 scnet)上,由于服务器负载较高、网络延迟不稳定,或者正在进行排队/认证,往往无法在 15 秒内完成响应,从而导致这个烦人的提示反复出现。

弹窗里其实已经给出了官方提示:“尝试关闭‘优化连接缓冲大小’”

这是 WinSCP 官方针对此类问题的直接建议。

  1. 打开 WinSCP,在登录界面(输入账号密码的那个界面)。
  2. 点击左下角的 “高级(A)…” 按钮。
  3. 在弹出的“高级站点设置”窗口左侧,展开 “连接©” -> 点击 “连接”
  4. 在右侧的设置列表中,找到 “优化连接缓冲大小”取消勾选它。
  5. 点击底部的 “确定” 保存,然后重新连接即可。

关闭“优化连接缓冲大小”的含义

简单来说,“优化连接缓冲大小”是 WinSCP 用来猜测网络传输数据包大小的一个“加速技巧”

关闭它的含义可以从以下三个方面来理解:

  1. 它在做什么?

    当这个选项开启时,WinSCP 在建立连接之初,会尝试探测你和服务器之间的网络链路,自动调整发送和接收数据的“缓冲区大小”,目的是为了让文件传输速度更快。

  2. 为什么要关掉?

    scnet这样的科研计算平台,服务器通常负载很高,或者网络路由比较复杂。WinSCP 的这次“探测”可能会因为服务器没来得及回应(超时),或者回应的数据不符合 WinSCP 的预期,反而导致连接初始化卡住,从而触发你看到的那个警告弹窗甚至连接失败。

  3. 关掉有什么影响?

    几乎没有坏影响。 关闭后,WinSCP 不再进行这个试探性的网络探测,而是直接使用一个标准的、保守的缓冲区大小来传输数据。虽然在某些特定网络下理论峰值传输速度可能略低一点点,但对于日常提交任务、上传下载脚本和常规文件来说,你完全感觉不到差别,却能换来稳定不报错的连接。

总结: 这相当于为了避开某个特定服务器的“握手小毛病”,放弃使用一个不太起眼的“网络加速猜测”,换取连接的稳定性。放心关掉即可。

网络错误

报错信息如下,这个和 mobaxterm 的 Network error应该是同一个报错,只是中英文的区别,解决办法就是保活

要解决 WinSCP 一段时间无操作后卡住/断连的问题,需在高级站点设置中配置 Keepalive(保活机制),让 WinSCP 定期向服务器发送“心跳包”,维持连接活性。以下是详细设置步骤:

步骤 1:进入高级站点设置

打开 WinSCP,点击左上角 “会话(S)” → 选择 “站点管理”(或直接按 F4)。

在弹出的“站点管理器”中,选中你要连接的站点,点击右下角的 “编辑(E)…”

步骤 2:打开“连接”选项卡的高级设置

在“编辑站点”窗口中,点击左下角的 “高级(A)…” 按钮。

设置如下,服务器响应超时改为 30秒;保活设置发送空SSH包,间隔秒数为 30秒。

报错解决思路

进不去就是退出刷新一下。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2019-2026 Vincere Zhou
  • 访问人数: | 浏览次数:

请我喝杯茶吧~

支付宝
微信