只读调查 · 10 月下旬的一次快照
登录节点没有宕机,是被拖慢了。大部分进程卡在等 IO,swap 已经用满。会话记录因为一个节点级故障不回收,又碰上一个客户端反复重连,积累了几千条。我们自己的占用很小,codex 也没有在泄漏。
Linux 的 load 把等 IO 的进程(D 状态)也算在内。load 503 而在跑的只有 19 个,说明机器不是算不过来,是卡在 NFS 读写和换页上。sshd 能回 banner,但登录还要走 PAM、建会话、读家目录,每一步都在排队。
从计算节点 ssh 到登录节点,条长 = 用了多少秒
vmstat 每秒采样,两次实时读数,单位 %
每次 ssh 登录,logind 都会记一条会话。这台机器有个节点级故障,有些会话结束后记录不回收,变成空壳,已经积累了几千条。最多的一个账号约有 2,500 条,过去一小时还在新增,看起来是某个客户端在反复重连,每次都起 bash 和 conda,conda 又卡在 NFS 上。这种"客户端反复重连、每次留下进程"的模式以前也出现过。
最多的一个账号和其余所有账号
按会话记录里的创建时间,只统计了前几名
D 状态进程,各次采样之间会浮动
几十个进程、不到 1 GiB 内存、大约 0.1 个核,不是这次的原因。快照里我们一度排 CPU 第一,那是测量用的 ps 自己:ps 的 %CPU 是累计 CPU 时间除以存活时间,刚启动的 ps 会显示几百 %。不过有两样东西按我们自己定的规矩不该在这台机器上。
| 东西 | 内存 | 结论 |
|---|---|---|
| 一个查看用的 tmux,每个窗口连一条 ssh 到会话所在的节点 | 约 11 MB | 正常,留着 |
| 一个 Claude Code 会话的副本,和它的 MCP 服务 | 约 420 MB | 不该在这里,此刻也卡在 IO 上。建议退掉,计算节点上那份照常工作 |
| Cursor 远程服务端,和两个成了孤儿的启动循环 | 约 134 MB | Cursor 连到了登录节点。改连计算节点后清掉 |
| 一个 Claude 远程服务 | 约 6 MB | 很小,可留 |
| 自己开着的几个终端 | 约 11 MB | 正常 |
没有。在任意计算节点上逐个试 codex 临时目录里的文件锁,加不上锁的就是还活着的 codex 进程,现在是 0 个。临时目录在快照前一周冒过一波,快照前两天以后就没有新的了。
按目录时间,快照前 19 天到快照当天;活着的 codex 进程:0
登录节点上能看 CPU、内存和会话记录;计算节点上只能看到 Slurm 的分配。下面的命令都是只读的。
# 登录节点:一条 ssh 抓全量快照(在计算节点上运行,脚本走 stdin) ssh -o BatchMode=yes -o ConnectTimeout=180 <登录节点> 'bash -s' < snapshot.sh # 按账号排:进程数、D 状态数、内存 GiB ps -e -o uid=,stat=,rss= | awk '{n[$1]++; if($2~/^D/)d[$1]++; m[$1]+=$3} END{for(u in n) printf "%s %d %d %.2f\n",u,n[u],d[u],m[u]/1048576}' | sort -k4 -rn | head # 按账号数会话记录 grep -h '^UID=' /run/systemd/sessions/* | sort | uniq -c | sort -rn | head # 瞬时 CPU:取 top 的第二轮 top -b -n 2 -d 2 | awk '/^top -/{n++} n==2' | head -30 # 全集群谁拿着多少 GPU(只有分配,看不到利用率) squeue -t R -h -o "%u %b" | awk 'match($2,/gpu:[a-z0-9_]+:[0-9]+/){split(substr($2,RSTART,RLENGTH),a,":"); g[$1" "a[2]]+=a[3]} END{for(k in g) print g[k], k}' | sort -rn | head # 某个节点的 CPU 负载、剩余内存、已分配资源 scontrol show node <节点> | grep -oE '(CPULoad|AllocTRES|FreeMem)=[^ ]+' # codex 在不在泄漏(任意计算节点,不用登录) cd ~/.codex/tmp/arg0; a=0; for f in */.lock; do [ -e "$f" ] || continue; flock -n "$f" true 2>/dev/null || a=$((a+1)); done; echo $a # 自己 job 里的 GPU 利用率(从别的 job 里跑要加 --export=ALL) srun --export=ALL --jobid=<自己的 job> --overlap nvidia-smi
pgrep -u 会报 invalid user name,看起来像什么都没找到。pkill -f 和 pgrep -f 会匹配到命令自己的 bash 外壳。用 [c]odex 这种写法,或者先 pgrep 再按 pid 处理。tmux capture-pane。这里的 tmux 版本有 bug,会让整个 tmux server 崩掉。loginctl terminate-session 对已经在 closing 的会话没用。空壳记录要找管理员处理。