深度排查:Slurm 任务提交触发 Socket 超时与 TCP 全连接队列溢出实战
- 问题现象
在高性能计算(HPC)集群中,用户在提交任务或任务链自动跳转时,频繁遇到以下报错:
终端/sbatch 报错: sbatch: error: Batch job submission failed: Socket timed out on send/recv operationSlurm 控制节点 (slurmctld.log) 报错:
[2026-03-18T06:52:21.334] JobId=9942 InitPrio=10000 usec=1719 [2026-03-18T06:52:21.334] error: slurm_send_node_msg: [socket:[979361678]] slurm_bufs_sendto(msg_type=RESPONSE_SUBMIT_BATCH_JOB) failed: Unexpected missing socket error更棘手的是,虽然生成了 JobID(如 9942),但由于前序任务(如 7842 FAILED)的 DependencyNeverSatisfied 状态,导致整个任务链陷入死锁。用户频繁重试、管理员疲于排查,问题持续恶化。
- 问题深度原因分析
经过对系统内核及网络状态的深入采样,我们发现了问题的根本原因:TCP 全连接队列(Accept Queue)溢出。
2.1 关键监控数据
通过 netstat -s 发现内核丢包计数严重异常:
[root@master ~]# netstat -s | grep -i "listen" 5304 times the listen queue of a socket overflowed 5307 SYNs to LISTEN sockets dropped这两个数字在短时间内急剧增长,清晰地表明 TCP 监听队列已经不堪重负。
2.2 逻辑拆解
问题的根源在于 Slurm 的 net.core.somaxconn 监听队列被塞满,让我们一步步拆解整个过程:
直接原因:
Slurm 控制守护进程(slurmctld)的 TCP 全连接队列长度达到上限(默认 128),新到达的连接请求被内核直接丢弃。
间接原因(业务逻辑):
集群启用了 job_submit 自定义插件进行权限校验(如 smlg_jobcheck),该插件执行需耗时约 2 秒。在任务提交高峰期,大量作业并发涌入,每个连接都需要经过插件处理才能完成 accept()。
木桶效应:
当同时等待处理的连接数超过 128 时,内核开始无情地丢弃(Drop)新连接,导致客户端报错 Unexpected missing socket。这就像一个繁忙的餐厅,接待台只能同时服务 128 位顾客,超过这个数量就只能让新来的顾客离开。
- 关键字段与配置含义说明
在排查和修复过程中,我们涉及了以下核心参数,理解它们的含义至关重要:
参数 所属层面 含义
net.core.somaxconn Linux 内核 定义了系统中每一个端口监听队列的最大长度(上限),默认值为 128,HPC 场景下明显不足
MessageTimeout Slurm 配置 Slurm 组件之间通讯的数据传输超时时间,建议在高负载集群设为 30-180s
TcpTimeout Slurm 配置 建立 TCP 连接本身的超时时间
Send-Q (ss 命令) 网络状态 在 LISTEN 状态下,表示该端口当前支持的最大全连接队列深度
Recv-Q (ss 命令) 网络状态 表示当前正在队列中等待程序 accept() 的连接数,如果持续 >0 且接近 Send-Q,说明队列正在积压
排查命令示例:
查看 Slurm 主端口的监听队列状态
ss -lntp | grep 6817输出示例:
LISTEN 0 128 *:6817 *:* users:(("slurmctld",pid=12345,fd=12))其中 128 就是当前的 Send-Q(最大队列深度)
- 解决方法与实施步骤
第一步:调大内核 TCP 监听上限
在管理节点修改内核参数,将"大门"放宽:
临时生效
sysctl -w net.core.somaxconn=2048 sysctl -w net.core.netdev_max_backlog=5000永久生效:编辑 /etc/sysctl.conf
echo "net.core.somaxconn = 2048" >> /etc/sysctl.conf echo "net.core.netdev_max_backlog = 5000" >> /etc/sysctl.conf参数说明:
somaxconn=2048:将监听队列上限从 128 提升到 2048
netdev_max_backlog=5000:增加网卡接收队列长度,防止丢包
第二步:同步更新 Slurm 全局配置
在 slurm.conf 中增加超时容错,防止因插件响应慢导致的断连:
编辑 /etc/slurm/slurm.conf
增加通讯耐心
MessageTimeout=180 TcpTimeout=10这两个参数的调整让 Slurm 组件之间更有耐心等待对方响应。
第三步:重启服务使应用层认账
关键提示: 修改 somaxconn 后,必须重启 slurmctld 进程,程序才会重新向内核申请更大的 Send-Q 空间。
systemctl restart slurmctld验证结果
ss -lntp | grep 6817此时 Send-Q 应该从 128 变为了你设置的内核上限(如 2048)
验证示例输出:
LISTEN 0 2048 *:6817 *:* users:(("slurmctld",pid=12345,fd=12))第四步:业务脚本增加容错(最佳实践)
即使后端再稳健,瞬时峰值仍可能存在。建议在任务提交脚本中加入重试机制:
bash
#!/bin/bash
监控队列溢出计数是否停止增长
watch -n 5 'netstat -s | grep -i "listen"'监控当前队列深度
watch -n 5 'ss -lntp | grep 6817'5.1 排查思路要点
Socket 超时问题不能只看应用层,需要从"整个链路"去排查
128 是 Linux 默认的保守设置,完全不适合 HPC 高并发场景
重启进程是让内核修改在应用层生效的必要步骤,这一步经常被忽略
监控 netstat -s 是判断网络溢出的最直观手段,应该作为常规监控指标