1、集群队列管理概述:什么是作业调度系统、常见的调度器对比(SLURM、PBS、LSF)、集群资源管理的基本概念
刚接触高性能计算集群的朋友,第一次登录上来往往一脸懵:
「我明明有 256 个核,为什么 job 跑不起来?」
「别人提交的任务怎么插到我前面去了?」
嗯,这背后其实藏着一个关键角色——作业调度系统。说白了,它就是集群的「交通指挥员」,决定了谁先上车、走哪条道、用多少座位。
什么是作业调度系统
作业调度系统(Job Scheduler)的核心职责就三件事:
- 资源分配——把 CPU、内存、GPU 这些硬件资源分给任务
- 任务排队——按优先级、资源需求、用户策略决定执行顺序
- 作业生命周期管理——从提交到运行到清理,全程接管
我记得早期帮某研究所搭集群时,用户直接 ssh 到计算节点手动跑程序,结果一个占满内存的进程把整个节点搞挂了。调度系统就是来治这种乱象的——让你别手贱,把资源管理交给机器。
一句话总结:没有调度系统的集群就是一盘散沙,谁抢到谁用,谁也保证不了稳定性。
常见调度器对比:SLURM、PBS、LSF
市面上主流的调度器就这三家。我三个都用过,也吃过不少苦头,这里直接上干货对比表。
| 特性 | SLURM | PBS (Torque/Moab) | LSF |
|---|---|---|---|
| 开源/商业 | 完全开源,GPL | 开源核心 + 商业扩展 | 商业软件(IBM) |
| 配置复杂度 | 中低,学起来快 | 中等,插件多 | 较高,依赖商业服务 |
| 可扩展性 | 极强,Top500 中大量使用 | 一般,万核以上吃力 | 强,适合大型企业 |
| 作业提交命令 | srun, sbatch, squeue | qsub, qstat, qdel | bsub, bjobs, bkill |
| GPU 管理 | 原生支持,非常成熟 | 需要额外配置 | 支持,但依赖版本 |
| 典型用户 | 学术、HPC 中心、AI 训练 | 老牌超算中心 | 金融、制造、企业 IT |
我个人习惯:新项目无脑选 SLURM。为什么?你想想看,现在 AI 训练几乎都是 SLURM + Kubernetes 的组合,社区活跃、文档全,遇到坑也能搜到答案。PBS 我在十多年前用过,那时候还是 Torque 的天下,后来慢慢被 SLURM 替代了。LSF 嘛,我在某大型药企见过,稳定是稳定,但一套 license 贵得离谱,小团队真用不起。
我的建议:如果团队小、预算有限,直接上 SLURM;如果公司有钱且有 IBM 生态绑定,LSF 也不是不能选。但记住,千万别自己魔改调度器——我曾经见一个团队在 PBS 上加了乱七八糟的插件,最后升级时全部废掉,血泪教训。
集群资源管理的基本概念
要玩转调度器,这几个概念你必须吃透。它们就像交通规则里的红绿灯、车道和限速牌。
节点(Node)
集群里的每一台物理机或虚拟机就是节点。节点分两种:
- 登录节点——你 ssh 上来写脚本、提交作业的地方,别在这跑计算
- 计算节点——真正干活的地方,调度器帮你把任务塞进去
我在项目中遇到过有人把深度学习训练直接跑在登录节点上,结果整个集群 200 多号人卡死了——嗯,后来我加了个 cgroup 限制才解决。
分区(Partition)/ 队列(Queue)
把计算节点分组管理。比如:
- gpu_queue:只放带 GPU 的节点
- debug_queue:小任务、短时间,用来调试
- bigmem_queue:内存特别大的节点
你提交作业时选哪个队列,调度器就把你扔到对应的节点组里。
作业(Job)与任务(Task)
作业是你提交的一个整体任务。任务是一个作业里的子单元——比如你用 MPI 并行跑了 64 个进程,每个进程就是一个 task。
# SLURM 示例:提交一个 4 节点、每节点 8 任务的 MPI 作业
sbatch --nodes=4 --ntasks-per-node=8 my_mpi_job.sh
说白了,你提交的不是命令,而是一个「资源请求书」。调度器看完你的请求,再看看空闲资源,决定什么时候让你跑。
资源分配策略
为什么你的作业老排在我前面?这背后是策略说了算:
- FIFO——先来后到,简单公平但效率低
- 公平共享(Fairshare)——每个用户/组按历史用量动态调整优先级
- 抢占(Preemption)——高优先级作业来了,低优先级的乖乖让位
- 回填(Backfill)——合理利用碎片资源,小作业插空跑
实际调度器会组合使用这些策略。比如 SLURM 默认用 Fairshare + Backfill,效率最高。
避坑经验:我曾经遇到过一位用户提交了 10000 个单核小作业,结果 Backfill 算法把整个集群的调度队列塞爆了。后来我给他加了一条限制:同一用户最多 500 个 running job。这种配置在 SLURM 里一行就能搞定:
MaxJobs = 500
MaxSubmitJobs = 10000
别等到出事了再补——先想清楚你的使用场景。
一张图看清调度系统全貌
下面这张 SVG 图展示了作业从提交到结束的完整生命周期,以及调度器在其中扮演的角色。你可以把它当作整章的「知识地图」。
这张图其实道出了调度系统的本质:排队、分配、执行、清理。你提交作业后,调度器会检查你有无权限、资源够不够、优先级高不高,然后决定是立刻跑还是等等再跑。跑完之后,调度器还要帮你释放资源,不给别人留麻烦。
小结
你可能会觉得这些东西很枯燥,但说实话,集群调度的底层逻辑和你在公司门口等出租车没什么两样。有人着急(高优先级),有人想拼车(并行作业),有人行李多(大内存需求),调度器就是那个「最理性的司机」。先把这些概念装进脑子里,后面几章我们上真家伙——写 SLURM 脚本、配队列、追查问题。