简介:Torque 6.1.1.1 是开源的集群资源管理与作业调度系统源码包,面向HPC集群管理员、运维工程师及需要二次开发的科研人员,用于搭建并管理由 pbs_server 服务端与 pbs_mom 计算节点组成的 Torque 集群环境。压缩包内共2000个文件,以C源码、C头文件、Makefile编译脚本、配置文件模板及日志文件为主体,并包含少量辅助脚本与文档,整体体积仅13.45MB,适合快速下载与编译。目前已有835人学习或下载,可作为上手 Torque 队列系统的实际参考。通过源码可深入理解作业提交、调度、执行及节点状态监控的核心流程;包内还提供安装配置样例、平台适配说明和排错辅助文件,便于在实践中完成集群部署、参数调优与问题定位。
1. TORQUE 6.1.1.1 是什么:不是普通压缩包,而是一套集群作业调度器
拿到 torque-6.1.1.1.tar.gz 这个文件,别把它当成普通源码包解压玩玩就完事。TORQUE 是一套脱胎于 PBS 的开源集群作业调度器,这个 6.1.1.1 版本是 6.x 系列里的补丁版,解决过 mom 重连、调度器内存增长这类实际毛病。它的核心价值一句话:当多台机器、多个用户、多个计算任务混在一起时,由它决定每个任务去哪台机器、占几个核、跑多久、谁排队谁先跑,还能把资源消耗记录留下来。如果你手头有五台以上 Linux 服务器,要跑仿真、数据处理或者批量计算,人工分配已经乱到不可维护,那这个包值得你花一个下午编译起来。本文按我平时搭集群的路线走:先讲组件模型和编译选型,再给一套最小可复现的安装启动命令,然后把队列配置和五个高频翻车现场摊开,最后落到可验证的进阶技巧上。
2. 装它之前:TORQUE 6 的组件模型和编译环境准备
2.1 pbs_server、pbs_mom、pbs_sched:一个调度器的三个零件
TORQUE 在架构上是典型的主从模型,核心进程有三个。pbs_server 是中心节点,维护所有作业状态、队列定义、节点清单,所有 qsub、qstat、qmgr 命令都是先连到它;pbs_sched 是调度器,按照队列属性和资源占用,决定哪个作业被分配到哪个节点;pbs_mom 跑在每台计算节点上,接收 server 下发的作业,替用户拉起脚本进程,再回传状态和资源数据。常见做法里还有第四个进程 trqauthd,它是认证守护进程,在配置了 munge 认证时才必须跑,纯 host 认证环境可以不管它。
理解这三个零件的关系,比背一百条命令都重要。装完系统后,你看到进程列表就能定位问题:只有 pbs_server 起来了,qsub 不报错,但作业永远停在 Q,因为没人做调度;只有 pbs_mom 起来了,pbsnodes -a 里所有节点全是 down;pbs_sched 异常退出,最典型的表现是队列里有作业、节点空闲,但调度器就是不动。所以排查的第一步永远是先看这三个进程在不在,而不是去翻队列配置。
这三个进程的启动顺序也有讲究。pbs_server 是老大,pbs_sched 和 pbs_mom 都依赖它;pbs_server 重启时,所有 mom 会断连,过一段时间自动重连,这个期间节点显示 down 是正常的。我见过有人一看到 down 就手动重启所有 mom,反而把重连状态搞乱。正确做法是给 mom 几分钟自动重连时间,再看 pbsnodes -a 的 state 列。
2.2 环境依赖清单:gcc、openssl-devel 与 boost 一个都不能少
源码编译第一步是装全依赖,这一步省了,后面 configure 会一遍一遍退出,非常消耗耐心。TORQUE 6.1.1.1 编译常见的依赖有这些:gcc、g++、make 是编译器基础;openssl-devel 提供加密库;libxml2-devel 是 XML 解析库;boost-devel 是 C++ 库,TORQUE 6 的调度器代码对 boost 有硬依赖。服务器上如果只装了运行库没装 -devel 开发包,configure 一样会失败,因为缺的是头文件而不是运行库。
包管理器命令按发行版替换,写法一般是:
yum install -y gcc gcc-c++ make openssl-devel libxml2-devel boost-devel # Debian/Ubuntu 系对应包名不同,常见是 gcc g++ make libssl-dev libxml2-dev libboost-all-dev这条命令里每个包都有明确用途:gcc 和 gcc-c++ 负责编译 C 和 C++ 代码,openssl-devel 提供认证相关的加密接口,libxml2-devel 用于解析集群配置里的 XML 片段,boost-devel 给调度器提供智能指针和线程工具。如果机器内存很小,并行编译会顶不住,建议关掉 -j 参数,后面第 3 章会展开。
configure 脚本对缺失库的处理方式很直接:打印一行错误就退出。所以不要在一长串输出里找原因,直接看最后几行。通常它会明确告诉你缺的是哪个头文件,比如找不到 boost 相关头文件,就是 boost-devel 没装。装完再跑一次 configure 即可,不需要重新解压。
2.3 configure 的三个关键选择:prefix、server-home 与认证方式
configure 参数决定了整个集群的数据根目录,装完再改非常麻烦,我一般会在这一步停下来想清楚。三个最关键的选项:--prefix 指定二进制安装位置,默认是 /usr/local,直接装在系统目录里也可以,但后续升级想换版本时,独立的 prefix 目录会干净很多;--with-server-home 指定调度数据目录,包括节点清单、作业日志、记账文件,默认是 /var/spool/torque;--disable-gui 关闭 TCL/TK 图形客户端 qmon 的编译,服务器上完全用命令行管理集群,这个选项可以减少依赖。
认证方式是在 configure 阶段另一个影响很大的决策。TORQUE 支持 host 认证和 munge 认证两种常见模式,host 认证是默认行为,原理是直接校验客户端的来源主机名是否在节点清单里,内网互信环境下最简单;munge 认证会为每个请求签发临时票据,需要额外部署 munge 服务,并保证所有节点上的 munge key 一致。初次搭建不推荐 munge,因为一旦 key 不同步,所有节点都认证失败,排查起来比编译问题更隐蔽。我逐渐形成的习惯是先 host 认证跑通全流程,再考虑要不要换 munge。
常见的 configure 组合写法如下:
./configure --prefix=/usr/local/torque \ --with-server-home=/var/spool/torque \ --disable-gui--with-server-home 这个参数容易被忽略源码包里既有的默认值。它影响的不只是服务器目录,m 节点日志路径、作业 spool 目录、记账文件全都在这个根路径下派生。后续所有日志路径的排查,比如 server_logs、mom_logs,都是跟着这个根路径走的,所以务必在 configure 时定下来,不要中途改。
3. 从 tar.gz 到三个进程在跑:TORQUE 编译安装与最小集群启动
3.1 解压、configure、make、make install 的最小命令序列
拿到 torque-6.1.1.1.tar.gz 后,第一步是解压进入源码树。整个编译安装的最小序列可以写成下面这样,按顺序执行即可:
tar zxvf torque-6.1.1.1.tar.gz cd torque-6.1.1.1 ./configure --prefix=/usr/local/torque \ --with-server-home=/var/spool/torque \ --disable-gui make -j4 make install这几条命令的逻辑很清楚:tar 解压得到源码目录;configure 根据第 2 章的参数生成 Makefile;make -j4 用 4 个并行任务编译,并行度要根据机器内存调整,内存小于 2GB 时建议直接 make;make install 把二进制、脚本、配置文件模板装到 /usr/local/torque 目录下。安装完成后,安装目录下的 bin 和 sbin 子目录里有全部管理命令,包括 pbs_server、pbs_mom、qsub、qmgr、pbsnodes。
编译失败时的信息要分阶段看。configure 阶段失败,基本是缺依赖头文件,按 2.2 补包;make 阶段失败,常见的是内存不足导致编译器进程被杀,或者 boost 库版本太老。如果是并行编译内存不足,改成单线程 make 通常能绕过。安装路径不要放在带空格的目录里,TORQUE 的脚本对路径空格处理得并不优雅,这个习惯能避免不少莫名其妙的问题。
make install 完成后,安装目录下会生成一个环境脚本,常见做法是把它 source 进当前 shell,或者在用户主目录的 .bashrc 里加一行,把 bin 和 sbin 目录写进 PATH。不 source 也能用,但要写全路径调用命令,排查问题时反而容易因为 PATH 顺序跑了系统里另一个版本的客户端,产生错觉。
3.2 配置 server_priv/nodes 与 /etc/hosts:让 server 认识每台节点
TORQUE 调度集群之前,pbs_server 必须知道有哪些计算节点、每台节点提供多少 CPU 槽位。这个信息写在 server-home 目录下的 server_priv/nodes 文件里。我一般先建目录再写文件:
mkdir -p /var/spool/torque/server_priv cat > /var/spool/torque/server_priv/nodes <<'EOF' node01 np=8 node02 np=8 node03 np=4 node_property=highmem EOF每行格式是节点名加属性,np=8 是关键属性,表示这台节点向调度器提供 8 个可分配的 CPU 槽位。调度器做资源匹配时,依据的就是这个数字,而不是操作系统实际核数,所以 np 值设错会导致节点长期显示 busy 或过载。node_property=highmem 是自定义标签,后面作业可以通过 #PBS -l nodes=1:highmem 来请求这类节点,实现简单分组调度。
集群里每个节点的主机名解析是另一个容易翻车的点。pbs_server 和 pbs_mom 之间通信靠主机名互相识别,DNS 不健全的内网环境,必须把所有节点短名和 IP 写进 /etc/hosts。配置 server_name 文件指向管理节点短名这一步也常被漏掉:
echo "mgmt01" > /var/spool/torque/server_nameserver_name 文件的作用是让 qsub、qmgr 这些客户端工具知道去连接哪台机器。如果这个文件没写,客户端会默认使用本机主机名,在多节点环境里直接连不上服务器。注意文件里写短名,不要写完整域名,否则后续认证阶段主机名比对会不一致,这是节点 down 的一大隐藏原因。
3.3 启动 pbs_server、pbs_mom、pbs_sched 并用 qstat 验证
节点清单和主机名解析就绪后,开始启动三个核心进程。首次启动 pbs_server 需要带上 -t create 参数创建服务器数据库,后续启动则不需要。启动顺序固定为 server 先行:
export PATH=/usr/local/torque/bin:/usr/local/torque/sbin:$PATH pbs_server -t create pbs_sched pbs_mom加环境变量的目的是让 qsub、pbsnodes 这些客户端命令在当前 shell 可用。pbs_server -t create 只在 /var/spool/torque 下还没有 server_db 时执行,如果数据库文件已存在,命令会报错退出,不会覆盖旧数据。pbs_sched 启动后没有任何前台输出,这是正常现象;pbs_mom 同样也是 daemon 方式运行,进程列表里能看到才说明真的起来了。
启动完成后的验证命令,我每次搭完集群都会输入一遍:
pbsnodes -a输出里每一台节点的 state 列如果是 down,说明 mom 还没注册成功;如果显示 free 或 job-exclusive,说明节点状态正常。刚启动的头几十秒显示 down 不用紧张,mom 在和 server 做第一次握手。另一个验证命令是 qstat -q,此时队列还没建,输出为空属正常,第 4 章会创建队列。到这里,最小集群的骨架已经立住了。
4. 建队列配节点:qmgr 九个命令把调度真正跑起来
4.1 队列的创建与启停属性:queue_type、enabled、started
进程都起了,但此时还没有队列,任何作业都投不进去。TORQUE 里的队列是作业的入口容器。队列分 execution 和 routing 两种类型,execution 队列直接运行作业,routing 队列只做转发,把作业按规则导到其他队列。小型集群通常只建一个 execution 队列就够了。创建和启停队列用的是 qmgr 命令,一连串配置可以写成:
qmgr -c "create queue batch" qmgr -c "set queue batch queue_type = execution" qmgr -c "set queue batch enabled = True" qmgr -c "set queue batch started = True" qmgr -c "set server default_queue = batch" qmgr -c "set server scheduling = True"这六条命令,前四条定义队列本身,后两条定义服务器级调度行为。enabled 属性控制队列是否接受新作业提交,started 属性控制队列里的作业是否真正开始执行。这两个属性是独立的,初学阶段最常踩的坑就是只设了 enabled 忘了 started,结果是 qsub 能提交、qstat 能看到作业,但作业永远停在 Q 状态不跑。scheduling = True 是服务器级的开关,如果它被关掉,整个调度器都不会分配作业,即使队列属性完全正常。
配置完成后用 qmgr -c "print queue batch" 查看队列属性,逐项核对 enabled、started、queue_type 三个字段。这套命令的另一个优点是幂等,重复执行教材命令不会报错,所以很多人会把 qmgr 配置写成 shell 脚本保存下来,每次重装集群直接跑一遍,这就是后面章节说的后悔药。
4.2 资源限制与节点分配参数:walltime、ncpus 与 properties
队列建好只是开始,真正的调度行为由一批 resources 前缀的参数控制。这些参数主要分三类:resources_max 是单作业上限,resources_default 是作业未声明资源时的兜底值,还有一批服务器级参数控制用户维度的限制。我每搭一个新集群,都会先把下面这些设一遍:
qmgr -c "set queue batch resources_max.walltime = 72:00:00" qmgr -c "set queue batch resources_max.ncpus = 16" qmgr -c "set queue batch resources_default.walltime = 01:00:00" qmgr -c "set queue batch resources_default.ncpus = 1" qmgr -c "set server max_user_run = 10"walltime 的格式是 HH:MM:SS,resources_max.walltime 限制单个作业最长运行 72 小时,超过这个值的作业在 qsub 阶段就会被拒绝。resources_max.ncpus 限制单作业最多请求核数,对防止有人一个作业占光全集群很有用。resources_default 的作用容易被低估:用户提交作业时不写 #PBS -l 资源请求,调度器就按默认值分配,不设默认 walltime 的话可能导致作业被赋予极小或极大的时间片。max_user_run = 10 是限制单个用户同时运行的作业数,资源不足时后续作业排队等待。
节点属性在调度匹配中的作用,我在这里单独说明一下。作业脚本里写 #PBS -l nodes=2:highmem 时,调度器只会从带 highmem 属性的节点里挑选。如果集群里没有这样的节点,作业会一直停在 Q 状态,而且 qstat -f 里看不到任何报错,只能通过对比属性和请求来判断。这个问题的隐蔽性很高,适合在出问题章节收藏。常见的关键资源参数汇总如下:
| 参数名 | 作用域 | 示例值 | 说明 |
|---|---|---|---|
| resources_max.walltime | queue | 72:00:00 | 单作业最长墙钟时间 |
| resources_max.ncpus | queue | 16 | 单作业最大核数 |
| resources_default.walltime | queue | 01:00:00 | 未声明时的默认时长 |
| max_user_run | server | 10 | 单用户并行业务数 |
| scheduling | server | True | 调度器总开关 |
| default_queue | server | batch | 未指定队列时的去向 |
4.3 提交第一个作业并用 qstat 验证调度结果
队列和资源参数就绪,可以提交第一个作业做端到端验证。TORQUE 的作业是一个脚本文件,头部用 #PBS 前缀写资源请求,后面的内容是实际要执行的命令。常见的最小作业脚本:
#!/bin/bash #PBS -N firstjob #PBS -q batch #PBS -l nodes=1:ppn=2,walltime=00:30:00 sleep 60 echo "job done"脚本前三行是作业声明:#PBS -N 给作业起名;#PBS -q 指定队列;#PBS -l 指定资源请求,nodes=1:ppn=2 表示要 1 个节点、每个节点 2 个 CPU 槽位,walltime 指定运行时长上限。提交和验证的命令组合如下:
qsub -V firstjob.pbs qstat -a qstat -f <job_id>-V 参数会把当前 shell 的环境变量带进作业进程,便于作业脚本访问用户在终端里导出的路径配置;qstat -a 以简表形式列出所有作业,状态列 Q 表示排队、R 表示运行、E 表示结束;qstat -f 查看作业完整属性,重点关注 state 字段和 exec_host 字段,后者能看到作业实际被分配到哪个节点。作业运行结束时,标准输出会写到作业目录下的 firstjob.o<job_id> 文件,标准错误写到 firstjob.e<job_id>。如果作业秒跑完且输出为空,先检查这两个文件。
从提交到 R 状态通常只需要几秒。如果作业停在 Q 状态,就去对照 2.2 节提到的那几个属性:queue started 是否为 True、scheduling 是否为 True、资源请求是否超过队列上限、是否有节点带对应属性。把这一条链路追下来,TORQUE 的基本调度模型就通透了。
5. TORQUE 6 避坑:五个常见的调度器翻车现场
5.1 节点一直 down,作业永远排队
这个现象排在第一位,因为它最打击新人信心。表象是 pbsnodes -a 显示节点 state 为 down,作业提交后永远停在 Q 状态,qstat 里看不到任何调度动作。原因排查按三句话来:主机名解析、认证匹配、mom 日志。
先把 /etc/hosts 打开看所有节点短名是否和实际主机名一致。server_name 文件里的名字也必须和 pbs_server 所在机器的主机名完全一致,不能写别名。如果 hosts 和 server_name 都没问题,下一站是 mom 日志,路径位于 server-home 目录下的 mom_priv/mom_logs,按日期命名的文件里搜索 error 或 cannot connect 关键字。常见做法是:
grep -i "cannot connect\|error" /var/spool/torque/mom_priv/mom_logs/$(date +%Y%m%d) | tail -20如果是认证失败,日志里会明确提示主机名不匹配。解决方法是统一所有节点的主机短名,并在 server 端重新读取节点列表。如果节点状态只是脏标记,可以用 pbsnodes -c 清理,这个操作会重置节点的错误状态,但前提是 mom 本身运行正常。清理完再 pbsnodes -a 确认 state 是否回到 free。
5.2 作业卡在 Q 或 H 状态不进入 R
现象是作业提交成功,qstat 里能看到,但几十个小时过去了状态还是 Q。这类问题有一个分水岭:必须搞清 Q 和 H 的区别。Q 是排队等待调度,H 是被人为挂起,两种状态的处置方式完全不同。
Q 状态的根源按优先级排查:队列 started 属性是否为 False、服务器 scheduling 是否为 False、作业请求的资源是否超过队列上限、请求的节点属性是否存在。这四个原因里,前两个是配置检查项,用 qmgr -c "print queue batch" 和 qmgr -c "print server" 一眼能看出;后两个要求对比作业脚本里的 #PBS -l 和队列资源上限,以及 pbsnodes -a 里的节点属性。注释里 qstat -f <job_id> 的 comment 字段有时会给出原因,但很多时候它不写,需要人工核对。
H 状态则是另一个故事。常见的触发原因是作业墙钟时间请求了半天、队列资源上限只有 1 小时,这类作业在 qsub 阶段就被拒收了;还有一种是用户主动 qhold 挂起。处置方式是找作业持有者确认,跑 qrls <job_id> 释放挂起状态。注意释放挂起前先确认资源是否满足,否则释放后还是会回到 Q。这块的经验是:遇到卡住的作业,先 qstat -f 看状态字母和注释字段,再对照队列配置做判断,不要直接重启服务,重启只能让问题更难定位。
5.3 qsub 报 cannot connect to server
现象是任何客户端命令,包括 qstat、qsub、qmgr,都报无法连接服务器。这个错误的迷惑之处在于,服务器看起来一切正常,进程在跑、端口在监听,但客户端就是连不上。
原因排查顺序也有讲究。第一是 client 端的环境变量和 PATH 是否指向正确的安装目录,如果机器上曾经装过其他版本,PATH 顺序会导致跑错二进制,报错信息还往往完全一样。第二是 server_name 文件是否存在、是否写了正确的服务器短名,这个文件位置在 /var/spool/torque/server_name。第三才是检查 pbs_server 是否真的在运行,看完后用 ps aux | grep pbs_server 确认。注意排查时带上完整路径调用命令,比如 /usr/local/torque/bin/qstat,避免 PATH 干扰。
解决路径也很直接:echo "mgmt01" > /var/spool/torque/server_name 重新写 server_name,再 source 一下环境脚本把 PATH 理顺。如果是为了排查而临时手动起了 pbs_server,记得当前 shell 里 export PBS_SERVER 环境变量的值要保持一致,这个变量优先级高于 server_name 文件,两者冲突会蛮奇怪地连不上。
5.4 时钟不同步让节点记录错乱
这是一个隐蔽问题。现象是节点明明没有作业在跑,pbsnodes -a 却显示 busy;作业明明运行了 10 分钟,记账文件里却是 0 秒。排查到最后才发现管理节点和计算节点的系统时钟存在几十秒偏差。
TORQUE 各组件之间通过心跳和数据包的时间戳来维护状态,时钟偏差一旦超过阈值,server 会认为 mom 的下发作业执行状态过期,产生资源占用还没有被回收的假象。另一个连带伤害是作业的 walltime 计算错乱,可能让调度器认为作业超时,触发强制终止。
解决方法是让全集群走同一时间源,常见做法是配置 chrony 或 NTP 服务,管理节点向外部时间源同步,计算节点向管理节点同步,并确认 timedatectl 状态里 NTP 为 active。临时没时间搭时间同步的话,先用 date 命令手动校准各节点,再重启 pbs_server 让状态重新收敛。注意顺序:先校时、再重启,顺序搞反了重启后还是一样乱。这块也算调度器搭建里最接近玄学的部分,时钟问题一旦排除,很多怪象自然消失。
5.5 重装和重启后的两个后悔药救场操作
现象一:pbs_server -t create 时报数据库已存在,无法创建;现象二:机器重启后,pbs_mom 注册不上,节点一直 down。这两个现象在重装集群和断电恢复时频繁出现,本质都是对 TORQUE 状态文件生命周期理解不深。
第一个问题的出路是认清 server_db 目录的性质。pbs_server -t create 只在数据库从未初始化时才能执行,一旦已存在,重复执行只会报错。如果确认集群不需要保留旧作业记录,可以先把 server_priv 目录整体备份,再清理 server_db 后重建;如果还想保留历史作业信息,不能用 -t create,而是要正常启动 pbs_server。第二个问题的出路是认清启动顺序:重启后 pbs_server 需要时间恢复数据库,pbs_mom 在这期间疯狂重试,表面上看起来像卡死,给足两分钟一般能自动连上。如果两分钟还不行,手动重启一次 mom,再观察 pbsnodes -a。
把 qmgr 配置写成脚本保存下来的习惯,我在 4.1 节提过一次,这里再强调一遍:这个脚本就是重装后的后悔药,重建集群时跑一遍脚本,队列和资源参数全部恢复,不用再手工敲几十条 qmgr 命令。我现在的习惯是配置脚本入库,谁改过队列规则一目了然。希望这一节的五个场景能帮你少走一半弯路。
6. 让调度结果可验证:作业数组与日志排查技巧
集群跑通后,日常干活的基本操作是批量提交相似任务。TORQUE 对这类场景有原生支持:作业数组。提交格式不复杂,在作业脚本里加一行 #PBS -t 0-9,一次提交就生成 10 个独立作业,每个作业里的 $PBS_ARRAYID 变量用于区分序号:
#!/bin/bash #PBS -N arrayjob #PBS -q batch #PBS -t 0-9 #PBS -l nodes=1:ppn=1,walltime=00:10:00 echo "task $PBS_ARRAYID start" sleep 10 echo "task $PBS_ARRAYID end"验证这批作业是否全部按预期跑完,除了 qstat -a 看总数,更可靠的方式是 qstat -f <job_id> 看单个作业的 resources_used.walltime 和 exit_status 字段。作业数组的另一个价值是单任务失败不影响其他任务,排查效率比写一个串行 for 循环高得多。我会在提醒习惯里同步一条:遇到结论异常的作业状态,先翻日志再动手。server 日志在 /var/spool/torque/server_logs/ 下按日期存放,快速过滤常见错误的命令:
grep -i "error\|denied\|cannot" /var/spool/torque/server_logs/$(date +%Y%m%d) | tail -50日志排查的意义在于,调度器会把很多无法通过 qstat 表面字段看出的原因写在日志里,包括认证失败、节点通信异常、调度器内部错误。我自己的习惯是第一次搭集群时把所有配置命令存成 shell 脚本入库,之后线上行为异常绝不凭感觉重启服务,而是先看 server_logs 和 mom_logs,再决定是清理节点状态还是调整队列属性。这套验证和排查的组合拳,让我在后续维护中没有再被调度状态反复折腾过。希望帮到你。
本文还有配套的精品资源,点击获取