3. 集群资源管理与调度器架构

在仿真计算集群中,调度器并不是一个孤立的“排队程序”,而是位于用户作业与物理资源之间的中枢系统。它向上接收用户提交的作业描述,向下管理计算节点的 CPU、内存、GPU、许可证等资源,并在中间通过队列、分区、账户等策略层完成资源分配与优先级裁决。理解调度器的组件与工作流程,是后续编写作业脚本、排查排队异常、优化资源利用率的基础。

一、调度器在集群中的位置与职责

从系统层次看,集群可分为四层:用户接入层(登录节点、Web 门户、API)、调度管理层(资源管理器与调度器)、计算执行层(计算节点与守护进程)、存储与网络层(共享文件系统、InfiniBand 等)。调度器位于第二层,其核心职责包括:

  • 资源发现与状态维护:持续收集各计算节点的 CPU 核数、内存容量、GPU 数量、当前负载、健康状态。
  • 作业接收与排队:接收用户提交的作业,解析资源请求、时限、队列、账户等属性,放入待调度队列。
  • 调度决策:按优先级、公平共享、回填、预留等策略,从队列中选择作业并匹配可用资源。
  • 作业启动与监控:在选定节点上启动作业进程,跟踪运行状态,处理超时、失败与资源回收。
  • 策略与配额管理:通过分区、队列、账户、QOS 等机制限制资源使用,保障公平性与优先级。

调度器不直接执行仿真程序,而是通过节点守护进程(如 Slurm 的 slurmd、PBS 的 pbs_mom、LSF 的 LIM 与 RES)在计算节点上拉起任务。因此,调度器是“决策者”,守护进程是“执行者”。

二、核心组件与对象模型

以 Slurm 为例,其架构包含以下关键组件:

  • slurmctld(中央管理守护进程):运行在控制节点,负责资源管理、作业调度、状态持久化。它是整个集群的“大脑”。
  • slurmd(节点守护进程):运行在每个计算节点,负责接收并执行来自 slurmctld 的任务,上报节点状态与资源使用。
  • slurmdbd(数据库守护进程):可选组件,用于将作业记录、账户信息写入数据库,支持 sacct 查询与公平共享策略。
  • 计算节点(Node):实际执行作业的服务器,具有名称、CPU 核数、内存、GPU、特性(Feature)等属性。
  • 分区(Partition):节点的逻辑分组,类似“资源池”。一个节点可属于多个分区。分区可设置默认时限、最大节点数、优先级、允许的账户等。
  • 队列(Queue):在 PBS/LSF 中常称队列,在 Slurm 中与分区概念高度重合。队列通常绑定特定资源集合与策略。
  • 作业(Job):用户提交的计算任务,包含资源请求、脚本、环境变量、依赖关系等。
  • 账户(Account)与 QOS:用于资源配额与优先级管理,常与项目经费、课题组绑定。

PBS 与 LSF 的组件命名不同,但角色对应:PBS 的 pbs_server 对应 slurmctld,pbs_mom 对应 slurmd,pbs_sched 对应调度策略模块;LSF 的 mbatchd 负责作业管理,mbschd 负责调度决策,LIM 负责节点资源监控。理解这些对应关系,有助于跨集群迁移作业脚本。

三、作业从提交到运行的工作流程

下面以 Slurm 为例,描述一个典型作业的完整生命周期:

  1. 提交:用户在登录节点执行 sbatch job.sh,slurmctld 接收作业并解析脚本中的 #SBATCH 指令,如 --partition=compute、--nodes=2、--ntasks-per-node=32、--time=04:00:00。
  2. 排队:作业进入指定分区的待调度队列,状态为 PENDING。调度器根据优先级、资源可用性、回填策略决定何时启动。
  3. 资源选择:调度器从空闲节点中筛选满足请求的节点集合,考虑节点特性、拓扑、许可证等约束。
  4. 启动:slurmctld 向选中节点的 slurmd 发送启动指令,slurmd 创建作业步骤(job step),执行用户脚本。
  5. 运行与监控:作业状态变为 RUNNING,slurmctld 持续跟踪资源使用;用户可用 squeue 查看状态,scontrol show job 查看详情。
  6. 完成与回收:作业结束后,slurmd 回收进程与资源,slurmctld 更新状态为 COMPLETED,并记录到 slurmdbd(若启用)。

在 PBS 中,流程类似:qsub 提交 → pbs_server 接收 → pbs_sched 调度 → pbs_mom 执行 → qstat 查看。LSF 则使用 bsub、bjobs、bkill 等命令。

Slurm 集群资源管理与调度架构 用户接入层 登录节点 Web 门户 / API sbatch / srun qsub / bsub 调度管理层(控制节点) slurmctld 中央管理守护进程 资源状态维护 作业调度决策 状态持久化 调度策略模块 优先级 / 公平共享 回填(Backfill) 预留(Reservation) 拓扑感知调度 slurmdbd 作业记录数据库 账户 / QOS sacct 查询 公平共享数据 分区 / 队列 compute gpu debug long 计算执行层(计算节点) 节点 node01 slurmd 64 核 / 256 GB 2×A100 GPU 节点 node02 slurmd 64 核 / 256 GB 2×A100 GPU 节点 node03 slurmd 32 核 / 128 GB 无 GPU 共享存储 Lustre / NFS 作业输入输出 结果归档 提交作业 资源请求 启动任务 分配资源 下发作业 状态上报 资源监控 作业提交 任务下发 状态上报

四、队列与分区的策略设计

分区与队列是调度器实现资源隔离与优先级控制的主要手段。一个合理的分区设计通常考虑以下维度:

  • 硬件差异:将 GPU 节点、大内存节点、普通 CPU 节点分入不同分区,避免小作业占用稀缺资源。
  • 作业时限:debug 分区限制 30 分钟,适合调试;long 分区允许 7 天,适合长时仿真。
  • 优先级与配额:高优先级分区面向紧急任务,但限制最大节点数;普通分区通过账户配额保障公平。
  • 访问控制:通过 AllowAccounts、AllowGroups 限制特定分区仅对某些课题组开放。

例如,一个典型的 Slurm 分区配置片段如下:

# slurm.conf 片段
PartitionName=debug Nodes=node[01-03] Default=YES MaxTime=00:30:00 State=UP
PartitionName=compute Nodes=node[01-10] MaxTime=24:00:00 State=UP
PartitionName=gpu Nodes=node[11-14] MaxTime=72:00:00 State=UP
PartitionName=long Nodes=node[01-10] MaxTime=7-00:00:00 State=UP

用户提交时通过 --partition=gpu 指定分区。若未指定,则使用默认分区。调度器在分区内按优先级排序,同时考虑回填:小作业可利用大作业预留的空隙提前运行,但不得延迟任何已排队作业的预计开始时间。

五、调度器职责的边界与常见误区

调度器负责“分配资源”,但不负责“优化用户程序”。常见误区包括:

  • 认为提交后就会立即运行:实际取决于资源可用性与优先级,PENDING 是正常状态。
  • 忽略资源请求的准确性:申请 64 核但实际只用 8 核,会浪费资源并降低自身后续作业优先级。
  • 混淆分区与物理节点:一个节点可属于多个分区,分区是逻辑视图,不是物理隔离。
  • 忽视账户与 QOS 限制:超出配额会导致作业被拒绝或降级,需提前确认项目账户余额与 QOS 上限。
排查作业长时间 PENDING 时,可按以下顺序检查:squeue -j <jobid> -o "%.18i %.9P %.8j %.8u %.2t %.10M %.6D %R" 查看排队原因;sinfo -p <partition> 查看分区节点状态;scontrol show job <jobid> 查看详细约束;sacctmgr show assoc user=$USER 确认账户配额。常见原因包括:资源请求超过分区上限、账户配额耗尽、QOS 限制、节点被预留或下线。

理解调度器的组件与工作流程后,下一步是掌握作业脚本的编写与资源请求的精确表达。调度器只根据你声明的资源需求做决策,声明越准确,排队与运行效率越高。