当前位置: 首页 > news >正文

Slurm作业管理核心操作指南:从提交到查询与修改

1. 从零到一:理解Slurm作业管理系统

如果你在高校的计算中心、研究所的机房或者任何规模稍大的计算集群上工作过,那么“Slurm”这个名字你一定不陌生。它不是什么美味佳肴,而是“Simple Linux Utility for Resource Management”的缩写,翻译过来就是“简单的Linux资源管理工具”。当然,这个“简单”是相对的,它指的是其架构设计理念清晰,但对于刚接触的用户来说,它的命令和概念可一点也不简单。简单来说,Slurm就是那个帮你向成百上千台计算节点“派活”的大管家。你告诉它:“我要跑一个需要128个CPU核心、256GB内存的程序,大概跑8小时。” Slurm就会在资源池里帮你找到符合条件的机器,把你的程序安排上去,并管理它的整个生命周期——从排队、运行到结束。今天,我们就来彻底盘一盘Slurm作业管理的那些核心操作:提交、查询、修改。这些是你与这个“大管家”打交道最频繁的日常,掌握了它们,你才能在集群上游刃有余。

为什么是Slurm?在超算和高性能计算领域,除了Slurm,还有PBS、LSF等作业调度系统。Slurm因其开源、灵活、与Linux生态结合紧密而广受欢迎,尤其是在学术界和科研机构。它的核心逻辑是“资源管理和作业调度”,你可以把它想象成一个高度智能化的任务分配中心。对于用户而言,你不再需要关心你的程序具体在哪台物理机器上运行,你只需要通过一套标准的命令接口,描述清楚你的任务需求即可。本篇文章,就是为你梳理这套接口中最常用、最核心的部分。无论你是刚开始接触集群计算的研一新生,还是需要偶尔使用超算资源的工程师,这篇文章都能帮你快速上手,避开我当年踩过的那些坑。

2. 作业提交:把你的计算任务交给Slurm

提交作业是与Slurm交互的第一步,也是最关键的一步。这一步决定了你的任务将以何种姿态进入调度队列,申请哪些资源,以及最终如何执行。Slurm提供了多种提交方式,从最简单的直接运行到复杂的批处理脚本,适应不同的应用场景。

2.1 交互式作业提交:快速测试与调试

当你需要快速测试一个命令、调试一个脚本,或者进行一些简单的交互式操作时,交互式作业是你的首选。它让你感觉就像登录到了一台专用的计算节点上一样。

最常用的命令是srun。例如,你想在一台拥有4个CPU核心的节点上启动一个交互式的bash shell,可以这样做:

srun --pty -N 1 -c 4 --mem=4G -t 01:00:00 bash

让我拆解一下这个命令:

  • srun: 这是发起实际作业执行的命令。对于交互式作业,我们通常用它。
  • --pty: 这是关键参数,代表“伪终端”。没有它,你无法获得一个可交互的shell。
  • -N 1: 指定需要1个计算节点。
  • -c 4: 指定需要4个CPU核心(即“cpus-per-task”)。
  • --mem=4G: 指定需要4GB的内存。注意,这里的内存是每个节点申请的总量,不是每个核心。
  • -t 01:00:00: 指定作业的最大运行时间,格式是时:分:秒。这里申请了1小时。时间一到,无论任务是否完成,作业都会被强制终止。
  • bash: 最后指定要运行的命令,这里就是启动一个bash shell。

执行成功后,你的命令行提示符可能会发生变化(比如显示主机名变了),这意味着你已经“跳转”到了Slurm分配给你的计算节点上。之后你就可以像在本地一样运行命令了。退出这个bash shell(输入exit),交互式作业也就结束了。

注意:交互式作业非常消耗资源,因为它会独占你申请的核心和内存,直到你手动退出。它只适合短期的、轻量的测试。长时间的计算任务绝不应该用交互式作业占用资源,而应该使用下面要讲的批处理作业。

2.2 批处理作业提交:主力计算任务的标准姿势

对于绝大多数正经的计算任务(仿真、数据分析、机器学习训练等),我们都使用批处理作业。你需要准备一个作业脚本,然后在登录节点(头节点)上使用sbatch命令提交它。

一个典型的作业脚本(比如叫my_job.sh)长这样:

#!/bin/bash #SBATCH -J MySimulation # 作业名,便于识别 #SBATCH -N 2 # 申请2个计算节点 #SBATCH --ntasks-per-node=32 # 每个节点上运行32个任务(通常对应MPI进程数) #SBATCH -c 2 # 每个任务分配2个CPU核心(用于多线程程序,如OpenMP) #SBATCH --mem-per-cpu=4G # 每个CPU核心分配4GB内存 #SBATCH -t 2-00:00:00 # 最大运行时间:2天 #SBATCH -o job.%j.out # 标准输出重定向到文件,%j会被替换为作业ID #SBATCH -e job.%j.err # 标准错误重定向到文件 #SBATCH -p compute # 指定提交到名为‘compute’的队列(分区) # 加载必要的环境模块(取决于集群配置) module load intel/2022.1 module load openmpi/4.1.3 # 进入作业启动的目录(默认是你的家目录,但建议显式切换到工作目录) cd $SLURM_SUBMIT_DIR # 执行你的计算程序 # 示例1:运行一个MPI并行程序 mpirun -np 64 ./my_mpi_app input.dat # 示例2:运行一个多线程程序 export OMP_NUM_THREADS=2 ./my_omp_app

提交这个脚本非常简单:

sbatch my_job.sh

提交成功后,Slurm会返回一个作业ID,例如Submitted batch job 1234567。这个ID是后续查询和管理作业的唯一凭证。

这里有几个至关重要的细节和心得:

  1. 资源申请策略-N,--ntasks-per-node,-c这几个参数的组合决定了资源视图。对于纯MPI程序(每个进程单线程),通常设置--ntasks-per-node-c 1。对于混合MPI+OpenMP程序,--ntasks-per-node指定MPI进程数,-c指定每个进程可用的OpenMP线程数。总核心数 = 节点数 × 每节点任务数 × 每任务核心数。申请时一定要匹配你程序的并行模式,否则会造成资源浪费或性能低下。
  2. 内存申请--mem--mem-per-cpu二选一。--mem申请每个节点的总内存,--mem-per-cpu申请每个核心的内存。后者更精细,也更容易被调度器满足。务必根据程序实际需求估算,申请过少会导致作业运行中因内存不足(OOM)被杀死;申请过多则会降低作业被调度的优先级,并浪费资源。
  3. 时间限制-t参数务必设置得比预估时间稍长一些,留出缓冲。但也不要长得离谱,因为很多集群的调度策略会优先调度短作业。精确预估作业时间是高效使用集群的关键技能之一。
  4. 输出文件:强烈建议使用-o-e重定向输出。计算节点的本地文件系统可能在作业结束后被清空,输出到你的家目录或项目目录更安全。%j通配符能自动加入作业ID,避免文件名冲突。

2.3 数组作业:批量处理同类任务的利器

如果你有成千上万个相互独立、只有输入参数不同的任务(例如参数扫描、处理大量独立的数据文件),一个个提交作业脚本是灾难性的。这时就该祭出数组作业这个大杀器。

数组作业允许你用单个作业脚本提交一系列相似的任务。Slurm会为每个任务分配一个唯一的数组索引($SLURM_ARRAY_TASK_ID),你可以在脚本里利用这个索引来区分不同的任务。

作业脚本示例array_job.sh

#!/bin/bash #SBATCH -J ArrayExample #SBATCH -N 1 #SBATCH -c 4 #SBATCH -t 01:00:00 #SBATCH --array=1-100%20 # 关键!定义数组索引从1到100,同时最多运行20个任务 # 假设你有一系列输入文件 input_1.dat, input_2.dat, ... input_100.dat INPUT_FILE="input_${SLURM_ARRAY_TASK_ID}.dat" OUTPUT_FILE="output_${SLURM_ARRAY_TASK_ID}.dat" ./my_program -i $INPUT_FILE -o $OUTPUT_FILE

提交后,Slurm会创建100个子任务(索引1到100),但根据%20的限制,最多只允许其中20个同时处于运行状态。这避免了瞬间占用过多资源,是一种友好的批量提交方式。

实操心得:数组作业的输出/错误文件默认会包含数组索引,如slurm-1234567_1.out。管理大量输出时,最好在脚本内根据索引创建子目录来归类存放结果,保持工作区整洁。

3. 作业查询:掌握任务的生命状态

作业提交后,它便进入了Slurm的调度系统。你不可能一直守着,必须通过查询命令来了解作业的状态、资源使用情况以及排队位置。这是日常运维和问题诊断的核心。

3.1 基础状态查询:squeue

squeue是你最常打的命令,用于查看作业队列的状态。

  • 查看所有用户的作业squeue
  • 查看自己的作业squeue -u $USERsqueue -u $(whoami)
  • 查看特定作业squeue -j <jobid>
  • 格式化输出,获取更详细信息
    squeue -u $USER -o "%.18i %.9P %.30j %.8u %.2t %.10M %.6D %.4C %.8m %R"
    这个自定义格式显示了作业ID、分区、作业名、用户、状态、运行时间、节点数、核心数、内存、节点列表,信息非常全面。你可以把这条命令设为别名,比如alias myq='squeue -u $USER -o ...‘

squeue输出的ST列(状态)是关键,常见状态有:

  • PD(Pending): 作业在排队,等待资源。这是最常见状态。
  • R(Running): 作业正在运行。
  • CG(Completing): 作业已完成,正在做收尾工作(如清理临时文件)。
  • F(Failed): 作业失败。
  • CA(Cancelled): 作业被取消。
  • TO(Timeout): 作业因超时被终止。

3.2 详尽的作业信息:scontrol show job

squeue提供的信息不够,或者你需要了解作业更底层的配置(比如它具体被分配到了哪些节点、它的资源请求详情)时,scontrol show job <jobid>是你的不二之选。

这个命令会输出一大段非常详细的信息,包括:

  • 作业的绝对路径和工作目录
  • 提交时指定的所有参数(资源、时间限制等)。
  • 分配到的具体节点列表
  • 作业的优先级、计费信息等

例如,当你的作业一直处于PD状态时,可以用这个命令查看其详细的资源请求,然后结合sinfo(查看分区和节点状态)命令,判断是否是资源请求过高(如内存、时间)导致没有合适节点,或者目标分区是否处于drain(维护)状态。

3.3 历史作业查询:sacct

squeue只能看当前在队列(包括运行和排队)中的作业。对于已经结束(无论成功失败)的作业,你需要使用会计命令sacct

  • 查看自己今天的所有作业sacct --format=JobID,JobName,Partition,Account,AllocCPUS,State,ExitCode,Start,End -S 00:00:00
  • 查看特定作业的详细信息sacct -j <jobid> --format=JobID,JobName,MaxRSS,Elapsed,State,ExitCode
    • MaxRSS字段非常有用,它显示了作业实际使用的最大物理内存。你可以用它来验证和调整你提交作业时申请的内存(--mem),避免下次申请过多或过少。
  • 查看某个时间段内失败的作业sacct -S 2024-01-01 -E 2024-01-31 --state=FAILED

sacct的输出可以帮助你进行作业统计、资源使用分析和问题回溯。例如,通过分析失败作业的ExitCode,可以判断是程序自身错误(非零退出码)还是被系统杀死(如OUT_OF_MEMORY)。

4. 作业控制与修改:动态管理你的任务

计划赶不上变化,有时我们需要对已提交的作业进行调整,比如修改参数、提前终止或者调整优先级。

4.1 修改排队中的作业:scontrol update

作业在PD(排队)状态时,大部分参数是可以修改的。这是Slurm一个非常人性化的功能。命令格式是:scontrol update jobid=<jobid> <parameter>=<new_value>

常见的可修改项包括:

  • 作业名scontrol update jobid=1234567 JobName=“NewName”
  • 时间限制scontrol update jobid=1234567 TimeLimit=3-12:00:00(改为3天12小时)
  • 分区(队列)scontrol update jobid=1234567 Partition=debug(从compute队列转到debug队列,debug队列通常优先级高、时间短)
  • 资源请求:可以增加或减少申请的节点数(NumNodes)、核心数(NumCPUs)、内存(MinMemoryNode)等。但注意:减少资源可能使作业立即满足条件被调度,增加资源则可能导致作业重新排队,因为原来的资源可能不满足新要求。

重要提示scontrol update只能修改排队中的作业。一旦作业进入R(运行)状态,大部分参数就无法再更改了。此外,有些集群可能禁用了部分参数的修改权限。

4.2 挂起与恢复作业:scontrol suspend/resume

这是一个高级但有时很有用的功能。你可以挂起一个正在运行的作业(状态变为S),释放其占用的CPU资源(但保留内存和分配状态),供更高优先级的作业临时使用。之后可以再恢复它。

  • 挂起:scontrol suspend <jobid>
  • 恢复:scontrol resume <jobid>

这个功能通常由管理员在紧急调度时使用。普通用户使用需谨慎,因为挂起期间你的程序进程会被“冻结”,不执行任何计算。

4.3 终止与取消作业:scancel

这是最常用的控制命令,用于删除作业。

  • 取消单个作业scancel <jobid>
  • 取消自己所有作业scancel -u $USER
  • 取消自己所有排队中的作业scancel -u $USER --state=PENDING
  • 取消数组作业中的特定任务scancel <jobid>_<array_index>(例如scancel 1234567_5
  • 取消数组作业的全部任务scancel <jobid>(和取消普通作业一样)

踩坑实录:曾经有一次,我误操作scancel -u $USER,瞬间杀掉了自己所有正在运行和排队的几十个作业,其中包括一个已经跑了三天的大型仿真,损失惨重。自那以后,我养成了两个习惯:第一,在运行超长作业的脚本里,用trap命令捕获终止信号,在作业被取消时自动保存一次中间结果;第二,取消作业前,先用squeue -u $USER确认一遍列表,或者使用更精确的scancel <jobid>

5. 高级查询与诊断技巧

掌握了基本命令后,一些组合拳和高级查询技巧能极大提升你的效率和对集群状况的洞察力。

5.1 资源使用效率分析

仅仅知道作业在运行还不够,你还需要知道它跑得“好不好”,资源利用是否充分。

  • 查看作业的实时资源使用:使用sstat命令。例如sstat -j <jobid> --format=JobID,MaxRSS,AveCPU,NTasks可以查看指定作业的内存和CPU使用情况。但这个命令通常需要在作业运行时,在提交作业的节点上执行,且依赖作业的cgroup配置,不是所有集群都默认允许用户使用。
  • 通过sacct进行事后分析:如前所述,sacct -j <jobid> --format=JobID,JobName,MaxRSS,Elapsed,State,ExitCode,CPUTime中的MaxRSS(最大内存)和CPUTime(总CPU时间)是核心指标。
    • CPU效率CPUTime是所用CPU核心时间的总和。理想情况下,一个使用64核、运行了1小时(3600秒)的作业,其CPUTime应接近64 * 3600 = 230400CPU秒。如果远小于这个值,说明你的程序并行效率不高,或者存在大量I/O等待、负载不均衡等问题。
    • 内存效率:对比MaxRSS和你申请的--mem--mem-per-cpu。如果MaxRSS远小于申请量,说明你申请了过多内存,下次可以减少,这样作业会更容易、更快地被调度。如果MaxRSS接近甚至超过申请量,作业就有因OOM被杀的风险,下次必须增加内存申请。

5.2 诊断作业排队与调度问题

作业一直排不上队(PD状态)是最让人头疼的。除了用scontrol show job看详情,还需要结合集群全局状态来分析。

  • 查看分区和节点状态sinfo命令是核心。
    • sinfo: 简要查看所有分区状态。
    • sinfo -s: 查看分区摘要,包括可用/空闲/占用/故障节点数,一目了然。
    • sinfo -N -o “%N %T %c %m %G”: 以节点为单位查看,显示节点名、状态、总核心数、总内存、使用的GPU信息。关注%T(状态)列:
      • idle: 节点空闲,可用。
      • alloc: 节点已被完全占用。
      • mix: 节点部分占用。
      • draindrain*: 节点正在被管理员维护或已下线,不可用。如果你的作业指定了某个处于drain状态的分区,它就会一直排队。
  • 查看作业的排队原因squeue -j <jobid> --start这个命令非常有用,它会尝试估算你的作业何时能够开始运行,并给出当前不能开始的原因。常见原因有:
    • Resources: 等待请求的资源(如特定规格的GPU、大内存节点)可用。
    • Priority: 有更高优先级的作业在你前面。
    • Dependency: 该作业在等待其依赖的另一个作业完成。
    • PartitionDown: 目标分区已关闭。 知道了原因,你就能做出应对:如果是资源请求太苛刻,考虑修改请求或换分区;如果是优先级问题,可能需要联系管理员或使用QOS(服务质量)特性。

5.3 利用环境变量与交互式调试

Slurm在作业运行时,会设置一系列非常有用的环境变量,你可以在作业脚本中利用它们。

  • SLURM_JOB_ID: 当前作业的ID。
  • SLURM_JOB_NODELIST: 分配给作业的节点列表。
  • SLURM_SUBMIT_DIR: 提交作业时所在的目录路径。在脚本开头cd $SLURM_SUBMIT_DIR是个好习惯,确保工作路径正确。
  • SLURM_CPUS_PER_TASK: 每个任务分配的CPU核心数(对应-c参数)。在OpenMP程序中,可以直接export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK
  • SLURM_ARRAY_TASK_ID: 数组作业中当前任务的索引号。

对于MPI作业,Slurm原生支持srun作为启动器,这比直接用mpirun更好,因为srun能更紧密地与Slurm的资源绑定结合,避免进程绑定错误。一个典型的MPI作业执行行是:

# 在作业脚本中,假设已通过 module load 加载了MPI环境 srun ./my_mpi_program

srun会自动从Slurm获取任务分布信息,无需指定-np参数。

6. 避坑指南与最佳实践

结合我多年使用和管理Slurm集群的经验,这里总结一些最容易出问题的地方和对应的解决方案,希望能帮你节省大量排错时间。

常见问题现象/错误根本原因与排查思路解决方案与预防措施
作业卡在PD状态不动squeue显示作业长时间PD1.资源请求过高:申请了不存在的节点规格(如超大内存)或时间过长。
2.目标分区不可用:分区处于draindown状态。
3.依赖未满足:定义了作业依赖(--dependency)。
4.用户/账户限制:达到作业数、核心数上限。
1. 使用scontrol show job <jobid>检查请求,用sinfo检查分区资源。调整请求或换分区。
2. 使用sinfo查看分区状态,换用其他可用分区(如debug)。
3. 使用scontrol show job查看Dependency字段。
4. 使用sacctmgr show user $USER查看账户限制。
作业运行中被杀死作业状态变为FAILEDCANCELLED,错误文件可能有Out Of MemoryTIMEOUT提示。1.实际内存超限:程序内存使用超出申请值(--mem)。
2.运行超时:程序运行时间超过-t指定的时间限制。
3.节点故障:运行节点硬件或网络故障。
1. 用sacct -j <jobid> --format=MaxRSS查看实际峰值内存。下次提交时增加内存申请(建议预留20%-30%余量)。对于内存波动大的程序,申请需格外宽松。
2. 合理预估时间,并设置稍长的时限。对于无法预估的作业,可分阶段提交或使用--time-min参数。
3. 查看作业错误输出和系统日志。可尝试重新提交。
MPI/并行程序性能差程序运行时间远长于预期,或sacct显示的CPUTime远小于核心数*运行时间1.进程/线程绑定错误:进程在CPU核心间频繁迁移,缓存失效。
2.通信瓶颈:节点内或节点间网络通信成为瓶颈。
3.负载不均衡:某些进程任务重,早早干完的进程在等待。
1. 使用srun而非mpirun启动,Slurm的srun默认绑定更好。可尝试在作业脚本中设置export SLURM_CPU_BIND=verbose查看绑定信息。
2. 对于跨节点作业,确保使用高速网络(如Infiniband)。在脚本中加载正确的MPI库(module load)。
3. 优化程序算法,实现负载均衡。
数组作业单个任务失败数组作业中,部分索引的任务失败,其他的成功。通常是任务相关的特定问题,如某个输入文件损坏、某个参数导致计算溢出等。1. 检查失败任务对应的错误文件(slurm-<jobid>_<index>.err)。
2. 可以单独重新提交失败的任务索引,使用sbatch --array=<failed_index> job_script.sh
找不到模块或命令作业错误输出显示module: command not found./my_program: No such file or directory1.环境变量未继承:作业脚本默认不会继承你登录shell的所有环境变量(如module路径)。
2.路径错误:程序或输入文件路径使用了相对路径,而作业的工作目录并非你想象的那个。
1. 在作业脚本中,必须使用module load显式加载所需的软件环境。不要依赖交互式shell的环境。
2. 在脚本开头使用cd $SLURM_SUBMIT_DIR或使用绝对路径来定位文件和程序。

最后再分享几个让我受益良多的小习惯:

  1. 脚本模板化:为自己常用的任务类型(如单节点多核、多节点MPI、GPU作业、数组作业)创建模板脚本。每次提交新作业时复制模板修改,能极大减少因参数遗漏或格式错误导致的提交失败。
  2. 善用--test-only参数:在正式提交前,使用sbatch --test-only my_job.sh。这个参数不会真正提交作业,而是会检查你的脚本语法、资源请求的合理性,并模拟一次调度,告诉你如果提交,作业将会被分配到哪个分区、满足什么条件。这是一个非常安全的“预演”手段。
  3. 输出目录管理:在作业脚本里,根据作业ID或日期创建独立的输出子目录(如mkdir -p output/job_${SLURM_JOB_ID}),然后把所有输出和错误文件都重定向到这个目录里。这样,几个月后你回来找结果时,不会面对一个满是slurm-*.out文件的混乱目录。
  4. 资源申请宁紧勿松:在保证作业稳定运行的前提下,尽可能精确地申请资源(特别是内存和时间)。更小的资源请求意味着更高的调度优先级和更短的排队时间,这对整个集群的利用率和你的工作效率都有好处。通过几次运行的sacct数据来不断校准你的申请值,是一个专业用户的标志。
http://www.jsqmd.com/news/1409849/

相关文章:

  • 内网即时通讯选型变化:政务、金融与制造单位更应按数据边界建设 - 小天互连即时通讯
  • 模块化智能体框架:合成约束下的多目标药物先导化合物优化
  • 从智己车机故障看OTA与嵌入式系统稳定性:排查与风险管控
  • Python免费学习资源全解析:从零基础到项目实战的完整路径
  • Windows截图工具Snipping Tool:从基础操作到高阶工作流集成
  • Walrus平台集成OpenTofu:可视化界面管理基础设施即代码实践
  • UOS系统Java开发环境搭建:OpenJDK与IntelliJ IDEA安装配置全攻略
  • 从零搭建视觉测距PID平衡球系统:原理、代码与调参实战
  • CAPL打印函数write/writeex/writelineex:车载网络调试与自动化测试核心技巧
  • Windows Server 2016远程桌面配置:从核心原理到安全实践
  • 基于STM32与ESP8266的自建MQTT OTA升级系统全解析
  • C语言指针从入门到精通:内存地址、数组、函数与动态内存管理
  • Jackson @JsonSerialize注解深度解析:自定义序列化实战与性能优化
  • Java强制类型转换:从ClassCastException到类型安全的深度解析
  • Windows操作系统发展史:从图形界面到NT内核的技术演进
  • CAPL打印函数write、writeEx、writeLineEx深度解析与实战应用
  • 多智能体协作与形式化验证:AI解决组合设计问题的实践探索
  • Walrus集成OpenTofu:统一管理基础设施即代码的实践指南
  • 从零代码录制到工程化实践:Playwright自动化测试与网页操作全解析
  • Oracle ORA-00604递归SQL错误深度解析:从原理到实战排查指南
  • Python常用代码大全:文件操作、数据处理与网络请求核心模板
  • 2026 年现阶段,黄山正规的油浸自冷变压器供应商有哪些,你家配电房的老设备总烧?藏在它背后的高效稳电秘诀,90%的电工都摸不清底-华屹变压器 - 行业推荐官-2
  • Source Insight:资深开发者必备的代码静态分析与阅读利器
  • 视频剪辑素材替换全攻略:从原理到实战,掌握非破坏性编辑核心技巧
  • 生物信息学入门:从湿实验到RNA-seq分析的四个实操步骤
  • 正定矩阵判别全解析:从特征值到Cholesky分解的实战指南
  • Three.js入门指南:从零搭建3D网页开发环境与核心概念解析
  • 2026 杭州公司注册代办怎么选?5 家正规财税机构对比盘点 - 同梦
  • MySQL查询语句体系构建:从基础语法到性能优化的实战指南
  • qPCR荧光标记技术全解析:从SYBR Green到TaqMan探针的选型与应用