4、作业调度系统:Slurm集群搭建与配置、GPU分区管理(Partition)、作业优先级与抢占策略
说到量化交易的GPU集群,作业调度系统是绕不开的核心组件。我个人习惯用Slurm,原因很简单——它开源、稳定,而且对GPU的支持非常成熟。你想想看,一个量化团队可能同时跑着回测、实盘、模型训练,如果没有一个靠谱的调度系统,GPU资源早就打起来了。
4.1 Slurm集群搭建与配置
搭建Slurm集群,说白了就是三件事:控制节点、计算节点、共享存储。我在项目中遇到过不少团队,一上来就搞复杂的高可用,结果连基本功能都没跑通。我的建议是——先搭一个单控制节点、多计算节点的最小集群,跑通了再考虑扩展。
安装过程其实不复杂,但有几个坑要注意。嗯,这里我直接给一个我常用的安装脚本片段:
# 控制节点(通常叫 master)
yum install -y slurm slurm-slurmctld munge munge-libs
systemctl enable munge
systemctl start munge
# 计算节点(通常叫 node01, node02...)
yum install -y slurm slurmd munge munge-libs
systemctl enable slurmd
systemctl start slurmd
配置文件的灵魂是 slurm.conf。我曾经因为一个参数配错,导致整个集群的GPU资源无法被识别。这里我贴一个我常用的配置模板:
# slurm.conf 核心配置
ClusterName=quant-cluster
SlurmctldHost=master
NodeName=node[01-04] CPUs=16 RealMemory=64000 Gres=gpu:4
PartitionName=gpu Nodes=node[01-04] Default=YES MaxTime=INFINITE State=UP
注意那个 Gres=gpu:4,这是告诉Slurm每个节点有4块GPU。如果不配这个,Slurm根本不知道你有GPU资源。我见过有人配了 Gres=gpu:4 但忘了在节点上装 slurmd 的GPU插件,结果作业提交后一直卡在PD状态——说白了就是调度器找不到可用的GPU。
NodeName 写成了 NodeName=node[01-04] 但实际主机名是 node1、node2,结果Slurm死活不认。记住,Slurm的节点名必须和主机名完全一致。
4.2 GPU分区管理(Partition)
分区管理,说白了就是把GPU资源按用途切分成不同的池子。我习惯把量化团队的GPU分成三个分区:
| 分区名 | 用途 | GPU数量 | 优先级 |
|---|---|---|---|
| prod | 实盘交易 | 4块 | 最高 |
| backtest | 回测任务 | 8块 | 中等 |
| dev | 模型开发 | 4块 | 最低 |
为什么要这么分?你想想看,实盘交易对延迟和稳定性要求极高,如果回测任务把GPU占满了,实盘信号延迟几毫秒可能就是几十万的损失。我在项目中就遇到过这种情况——回测任务把GPU跑满了,实盘信号排队等了3秒,结果错过了最佳交易时机。
分区配置其实很简单,在 slurm.conf 里加几行就行:
PartitionName=prod Nodes=node01 Default=NO MaxTime=INFINITE State=UP Priority=100
PartitionName=backtest Nodes=node02,node03 Default=YES MaxTime=72:00:00 State=UP Priority=50
PartitionName=dev Nodes=node04 Default=NO MaxTime=24:00:00 State=UP Priority=10
这里有个小技巧——我把 backtest 设为默认分区,这样开发人员提交作业时如果不指定分区,自动进入回测分区,不会误占实盘资源。嗯,这个细节很重要。
MaxTime 限制。比如开发分区最多跑24小时,防止有人提交一个训练任务就跑一周,把资源锁死。我曾经遇到过有人提交了一个忘记设时间限制的训练任务,跑了整整两周,其他团队的模型开发全被堵住了。
4.3 作业优先级与抢占策略
优先级和抢占,这是调度系统里最考验设计能力的地方。说白了,就是当资源不够时,谁先上、谁被踢下来。
Slurm的优先级计算支持多种因子:
- Fairshare:按用户或组的资源使用历史动态调整
- Priority:手动设置的固定优先级
- Age:作业等待时间越长,优先级越高
- QOS:服务质量等级,可以理解为VIP通道
我个人习惯用 Priority + QOS 的组合。实盘交易用最高QOS,回测用中等,开发用最低。这样当实盘任务提交时,可以抢占正在运行的开发任务。
抢占策略的配置如下:
# 在 slurm.conf 中启用抢占
PreemptMode=REQUEUE
PreemptType=preempt/partition_prio
PreemptExemptTime=00:05:00
# 定义QOS
sacctmgr add qos prod_qos Priority=1000
sacctmgr add qos backtest_qos Priority=500
sacctmgr add qos dev_qos Priority=100
# 将用户关联到QOS
sacctmgr add user zhangsan qos=prod_qos,backtest_qos,dev_qos
这里有个关键参数 PreemptExemptTime=00:05:00,意思是作业运行5分钟内不会被抢占。为什么要设这个?你想想看,如果一个模型训练刚跑了1分钟就被抢占,那之前的计算全白费了。给5分钟的缓冲期,至少让作业完成一个checkpoint。
PreemptExemptTime 和 MaxSubmitJobs 限制,才解决了这个问题。
最后,我建议用 sacct 命令定期检查作业历史,看看抢占是否合理。如果发现某个用户的作业频繁被抢占,可能需要调整他的QOS或者给他分配专属资源。
slurm.conf 里设置 PriorityWeightAge=1000,让等待时间较长的作业自动提升优先级。这样即使开发任务被抢占,等一段时间后也能获得较高的优先级,不至于永远排不上队。
好了,关于Slurm集群搭建、分区管理和优先级抢占,核心内容就这些。记住一句话——调度策略的设计,本质上是在资源利用率和任务公平性之间找平衡。没有完美的配置,只有最适合你团队场景的方案。