找到 Slurm 集群中的蛀虫!
零 概述
一个高性能集群通常由上百个节点组成,它们一般有着相同的硬件条件和操作系统,提供给科学计算的用户提交作业使用。但有时 Slurm 集群会出现用户作业进程残留的情况,这就需要一个工具可以找到集群上有问题的节点反馈给管理员,以免影响其他用户作业。
基于这样的目的,笔者编写了一个适用于 Slurm 集群的排查工具,基于此工具,管理员可以轻松找出当前集群中有哪些节点不正常,比如这个节点明明没有被提交作业,但是 CPU 利用率却居高不下。或 GPU 节点没有被申请用卡,显存却被占着。此脚本工具可以罗列出这些有问题的节点,管理员可以定时执行此脚本,通过编写邮件服务或 Zabbix 报警项,来及时发现并处理这些节点。
一 快速开始
# 获取脚本
wget https://mirrors.qiql.net/script/findmoth-0.0.1.sh
# 赋予可执行权限
chmod +x findmoth-0.0.1.sh
# 查看使用说明
./findmoth-0.0.1.sh -h
# 编写主机名输入文件 nodelist,主机名以空格或换行符分隔
./findmoth-0.0.1.sh -c ./nodelist
二 前置条件
本工具基于批处理管理工具 Pdsh,一般 Slurm 集群都有一个可以执行批处理命令的管理节点,使用本工具需要该管理节点可以免密登录到集群的其他节点上执行命令,另外本工具的命令行参数解析部分使用了getopt,一般操作系统上都会有此包
三 判断逻辑
本工具适用于针对 CPU 和 GPU 的节点:
-
针对 CPU 节点,仅判断 CPU 的利用率是否小于理论 CPU 利用率(被申请的 CPU 核数/节点总 CPU 核数),内存的计算方法比较复杂,没有写入到判断逻辑中,会在后续版本中进行更新
-
针对 GPU 节点,仅判断 GPU 的利用率是否小于理论 GPU 利用率(被申请的 GPU 卡数/节点总 GPU 卡数)和显存利用率是否小于理论显存利用率(被申请的 GPU 卡数/节点总 GPU 卡数)
四 输入方式
一般 Slurm 集群的节点较多,命名规则也比较复杂,所以本工具以主机名文件的形式向脚本输入主机名,在工作目录编写一个名为 host-cpu.txt
的 CPU 节点主机名文件,可以用空格或换行来分隔主机名:
node001
node002
node003
node004
...
或:
node001 node002 node003 ...
或:
node001 node002
node003
node004
...
然后执行命令:
./findmoth-0.0.1.sh -c host-cpu.txt
就可以等待输入扫描集群中有问题的节点了,实测出来扫描一个节点大概需要一秒钟。
GPU 的输入方式同理
五 阈值判定
集群中的节点空载时,CPU 利用率也不一定是完全的 0%,会有一个 0% - 0.5% 的波动区间,脚本中默认将这个阈值设置为了 0.3。您可以通过命令行参数 -t, --threshold
来手动设置可以接受的阈值。注意:此阈值不对GPU节点生效!
六 核心代码
############################################
### CPU节点
############################################
# 设置阈值
local threshold=0.3
# 查询 CPU 节点当前的 CPU 利用率
local cur_cpu_util=$(pdsh -w ${hostname} top -b -n 1 | grep -oE '%Cpu\(s\):.*' | awk '{print $2}')
# 查询 CPU 节点当前的内存利用率
local cur_mem_util=$(pdsh -w ${hostname} free -m | sed 's/[^ ]*://' | awk 'NR==2{print $3/$2 * 100}')
# 查询 CPU 节点一共有多少核心
local all_cpus=$(scontrol show node ${hostname}| grep -oP 'CfgTRES=.*?cpu=\K\d+')
# 查询 CPU 节点当前被申请了多少核心
local alloc_cpus=$(scontrol show node ${hostname} | grep -oP 'AllocTRES=cpu=\K\d+')
if [ ! -n "$alloc_cpus" ];then
alloc_cpus=0
fi
# 计算 CPU 节点最大理论 CPU 利用率
local max_cpus=$(awk -v a="${alloc_cpus}" -v b="${all_cpus}" 'BEGIN{ printf "%.2f", a/b }')
# 判断是否异常
if [ `echo "${cur_cpu_util} <= ${max_cpus} "|bc` -eq 1 ] ; then
is_moth=0
fi
if [ $(echo "${cur_cpu_util} - ${max_cpus} <= ${threshold}" | bc) -eq 1 ]; then
is_moth=0
fi
############################################
### GPU 节点
############################################
# 查询 GPU 节点当前的 GPU 总利用率:
local cur_gpu_util=$(pdsh -w ${hostname} nvidia-smi --format=csv --query-gpu=utilization.gpu | tail -n+2 | sed 's/.*://; s/ \+%//' | awk '{ sum += $1 } END { printf "%.2f\n", sum }')
# 查询 GPU 节点当前的显存总利用率
local cur_mem_util=$(pdsh -w ${hostname} nvidia-smi --format=csv --query-gpu=utilization.memory | tail -n+2 | sed 's/.*://; s/ \+%//' | awk '{ sum += $1 } END { printf "%.2f\n", sum }')
# 查询 GPU 节点总 GPU 数:
local all_gpus=$(scontrol show node ${hostname} | grep -oP 'CfgTRES=.*?(?<=:tesla=)(\d+)' | awk -F= '{print $6}')
# 查询节点已被申请的 GPU 卡数
local alloc_gpus=$(scontrol show node ${hostname} | grep -oP 'AllocTRES=.*?(?<=:tesla=)(\d+)' | awk -F= '{print $4}')
if [ ! -n "$alloc_gpus" ];then
alloc_gpus=0
fi
# 计算 GPU 节点最大理论利用率,如果是八卡,最大理论利用率为 800%
local max_gpus=$((alloc_gpus * 100))
# 判断是否异常
if [ `echo "${cur_gpu_util} <= ${max_gpus} "|bc` -eq 1 ] ; then
if [ `echo "${cur_mem_util} <= ${max_gpus} "|bc` -eq 1 ] ; then
is_moth=0
fi
fi
评论区