系统资源监控:htop/iotop/nmon/du
生信服务器的三类典型故障:(1) 未限制线程数导致 CPU 打满、SSH 无法连接;(2) 临时文件写爆 root 分区导致 BAM 损坏;(3) 内存泄漏触发 OOM Killer 杀进程。本文覆盖四类监控:进程(htop)、磁盘(iotop/du/ncdu)、内存(free/vmstat)、长期趋势(nmon/sar),附 6 个实战案例和 7 个踩坑记录。
环境:Debian 12,128 核 / 512GB 内存 / 10TB 存储(典型生信服务器配置)。
1. CPU与进程监控——htop 一屏看尽
1.1 安装与基础
sudo apt install htop -yhtop进入 htop 后的界面布局(从上到下):
| 区域 | 内容 | 生信关注点 |
|---|---|---|
| 顶部仪表盘 | CPU 条(每核心一个)、内存条、swap条 | 绿色=用户态,红色=内核态,蓝色=低优先级 |
| 进程列表 | PID、USER、CPU%、MEM%、COMMAND | 谁的CPU%最高?谁在大量读写? |
| 底部快捷键 | F1-F10 | F6 排序、F9 kill、F5 树形视图 |
1.2 生信必备 htop 操作
# 启动时就按CPU排序htop -s PERCENT_CPU
# 只看某个用户的进程htop -u bioinfo
# 树形视图看父子进程关系# 在htop里按 F5,或者启动时:htop -t
# 只显示特定进程(配合 -p)htop -p $(pgrep -d, bwa) # 只看bwa的所有进程树形视图在生信中的妙用:当你用 GNU Parallel 或 Snakemake 提交了几十个任务,树形视图能一眼看出哪个主进程卡住了多少子进程。
1.3 htop 里的颜色条解读
对于生信工作负载,最常见的模式:
- 全是绿色(用户态CPU):正常——BWA/HISAT2 等计算密集型
- 大量红色(内核态CPU):⚠ 大量系统调用或 I/O 等待——可能是磁盘瓶颈
- 灰色(I/O Wait):⚠⚠ 进程在等磁盘——你的 RAID 阵列或 NFS 跟不上
- 蓝绿色(低优先级 nice):有人在后台跑 low-priority 任务
如果看到持续高 I/O Wait(>20%),问题不在 CPU 而在磁盘,接着看 iotop。
1.4 命令行快速采样
# 一次性快照(类似top -bn1但更漂亮)htop -C # 无颜色单色模式,适合重定向到文件
# 批量采样for i in {1..10}; do echo "=== Sample $i at $(date) ===" ps aux --sort=-%cpu | head -6 sleep 5done > cpu_samples.log2. 内存监控——OOM之前的黄金5分钟
2.1 free——第一眼看内存
free -h输出解读:
total used free shared buff/cache availableMem: 503Gi 198Gi 5.2Gi 2.1Gi 299Gi 300GiSwap: 32Gi 12Gi 20Gi生信重点看 available 不是 free!Linux 会大量使用内存做缓存(buff/cache),free 列看起来很少但 available 才是真正可分配给新进程的。
2.2 进程内存排名
# 按内存使用排序前10ps aux --sort=-%mem | head -11
# 只看RSS(物理内存),更准确ps -eo pid,user,rss,comm --sort=-rss | head -20 | \ awk '{printf "%-8s %-10s %-12s %s\n", $1, $2, sprintf("%.1fG", $3/1048576), $4}'
# 或者用更直观的ps aux | awk '{print $6/1024 " MB\t" $11}' | sort -rn | head -102.3 实时监控内存的脚本
#!/bin/bash# monitor_mem.sh —— 当可用内存低于阈值时告警THRESHOLD_GB=20INTERVAL=30
while true; do available_kb=$(grep MemAvailable /proc/meminfo | awk '{print $2}') available_gb=$((available_kb / 1048576))
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
if [[ ${available_gb} -lt ${THRESHOLD_GB} ]]; then echo "[${timestamp}] ⚠ WARNING: Only ${available_gb}GB available!" | tee -a mem_alerts.log
# 显示内存使用TOP5 echo "Top 5 memory consumers:" >> mem_alerts.log ps aux --sort=-%mem | head -6 >> mem_alerts.log else echo "[${timestamp}] OK: ${available_gb}GB available" fi
sleep ${INTERVAL}done2.4 OOM Killer 日志分析
# 查看OOM事件dmesg | grep -i "killed process" | tail -20
# 或者journalctl -k | grep -i oom | tail -20
# 典型输出:# Out of memory: Killed process 12345 (bwa) total-vm:64GB, anon-rss:58GB生信预防OOM的经验:
- 估算每个进程的内存:BWA mem 约需
参考基因组大小 × 1.5 + reads大小的内存 - 限制并发数 =
总可用内存 / 单进程峰值内存 - 给关键系统留 10-20GB 缓冲
- 跑大任务前
free -h确认
3. 磁盘IO监控——BAM写入的隐形瓶颈
生信最容易被忽略的瓶颈是磁盘 I/O。比对本身是 CPU 密集,但读写 FASTQ 和 BAM 才是真正的吞吐量杀手。
3.1 iostat——IO吞吐概览
# 安装sudo apt install sysstat -y
# 持续监控(每秒刷新)iostat -x 1
# 只看某个设备iostat -x -p sda 1关注列:
| 列 | 含义 | 健康值 | 危险值 |
|---|---|---|---|
r/s w/s | 每秒读写次数 | <1000 | >5000 (随机IO瓶颈) |
rkB/s wkB/s | 每秒读写KB | 取决于磁盘 | 接近磁盘标称值 |
%util | 磁盘繁忙度 | <70% | >90%(持续) |
await | 平均IO等待(ms) | <10ms(SSD) | >50ms |
aqu-sz | 平均队列长度 | <5 | >20 |
生信典型场景的 iostat 解读:
一个 50GB 的 BAM,如果 wkB/s 稳定在 200MB/s,大约需要 250 秒。如果 %util 已经到了 98% 但 wkB/s 只有 50MB/s——说明你在用机械硬盘,考虑换 SSD 或用 /dev/shm 做临时目录。
3.2 iotop——谁在疯狂读写
sudo apt install iotop -ysudo iotop -o # -o 只显示有IO活动的进程iotop 直接告诉你:哪个进程在读写、读了多少、写了多少、I/O 占用百分比。
# 生信典型输出:# PID DISK READ DISK WRITE COMMAND# 12345 200M/s 180M/s bwa mem# 12346 0M/s 150M/s samtools sort看到 samtools sort 大量写入临时文件时,考虑:
# 把临时目录放到内存(/dev/shm)或快速SSDexport TMPDIR=/dev/shmsamtools sort -T /dev/shm/sort_tmp -@ 16 input.bam -o output.bam3.3 磁盘空间——du和ncdu
# 查看各目录的空间占用du -h --max-depth=2 /opt/bioinfo | sort -rh | head -20
# 只看大于1GB的文件find /data -type f -size +1G -exec ls -lh {} \; 2>/dev/null | awk '{print $5, $NF}'
# ncdu —— 交互式磁盘分析(超级推荐!)sudo apt install ncdu -yncdu /datancdu 可以按 d 删除、按 n 按名称排序、按 s 按大小排序。找到谁把磁盘吃光了,按一下 d 直接删。
4. 长期监控——nmon记录一切
跑一个 48 小时的流程,过程中不可能一直盯着屏幕。nmon 能记录所有指标到文件,事后分析。
sudo apt install nmon -y
# 每30秒采集一次,持续24小时(2880个快照)nmon -f -s 30 -c 2880 -m /opt/logs/nmon/
# -f: 输出到文件(默认命名 hostname_YYYYMMDD_HHMM.nmon)# -s 30: 每30秒采样# -c 2880: 采样2880次# -m: 输出目录
# 用nmonchart把.nmon转成图表# 或直接用 nmon 打开 .nmon 文件:nmon -r /opt/logs/nmon/server_20250101_1200.nmon分析nmon数据的关键指标
在 nmon 文件中按对应键查看:
| 按键 | 内容 | 生信用途 |
|---|---|---|
c | CPU | 看计算密集型步骤的CPU利用率 |
m | 内存 | 有没有内存泄漏(持续增长) |
d | 磁盘 | 读写带宽、IOPS |
n | 网络 | NFS/数据传输 |
t | 进程 | 各进程资源占用排序 |
发现内存泄漏的nmon特征:内存 used 持续线性增长,即使进程数不变。对应地去找那个随运行时间增长内存的进程。
5. 生信实战:全流程监控脚本
#!/bin/bash# pipeline_monitor.sh —— 跑流程的同时记录资源set -euo pipefail
LOG_DIR="./monitor_logs"mkdir -p "${LOG_DIR}"PREFIX="${LOG_DIR}/$(date +%Y%m%d_%H%M%S)"
# 启动后台监控echo "Starting monitoring..."
# 1. CPU + 内存(每30秒)( echo "timestamp,cpu_user,cpu_sys,cpu_idle,cpu_wait,mem_total_kb,mem_avail_kb,swap_used_kb" while true; do ts=$(date +%s) cpu_line=$(top -bn1 | grep "Cpu(s)" | sed 's/[,%]/ /g') cpu_user=$(echo "$cpu_line" | awk '{print $2}') cpu_sys=$(echo "$cpu_line" | awk '{print $4}') cpu_idle=$(echo "$cpu_line" | awk '{print $8}') cpu_wait=$(echo "$cpu_line" | awk '{print $10}')
mem_info=$(free -k | grep Mem:) mem_total=$(echo "$mem_info" | awk '{print $2}') mem_avail=$(echo "$mem_info" | awk '{print $7}') swap_used=$(free -k | grep Swap: | awk '{print $3}')
echo "${ts},${cpu_user},${cpu_sys},${cpu_idle},${cpu_wait},${mem_total},${mem_avail},${swap_used}" sleep 30 done) > "${PREFIX}_cpu_mem.csv" &MONITOR_PID=$!
# 2. 磁盘使用(每5分钟)( echo "timestamp,path,used_percent,avail_gb" while true; do ts=$(date +%s) df -h /data /tmp / | tail -n +2 | while read -r fs size used avail pct mnt; do echo "${ts},${mnt},${pct%\%},${avail}" done sleep 300 done) > "${PREFIX}_disk.csv" &DISK_PID=$!
# 3. 进程快照(每10分钟)( while true; do echo "=== $(date) ===" ps aux --sort=-%mem | head -16 echo "" sleep 600 done) > "${PREFIX}_processes.log" &PROC_PID=$!
# ========== 主流程(替换成你的实际流程) ==========echo "Starting main pipeline at $(date)" | tee "${PREFIX}_events.log"
# 这里放你的实际生信流程# fastp -i ... -I ... -o ... -O ...# bwa mem ... | samtools sort ...# bcftools mpileup ...
echo "Pipeline finished at $(date)" | tee -a "${PREFIX}_events.log"
# ========== 停止监控 ==========kill ${MONITOR_PID} ${DISK_PID} ${PROC_PID} 2>/dev/null || truewait ${MONITOR_PID} ${DISK_PID} ${PROC_PID} 2>/dev/null || true
echo "Monitoring logs saved to: ${LOG_DIR}/"echo " CPU/Memory: ${PREFIX}_cpu_mem.csv"echo " Disk: ${PREFIX}_disk.csv"echo " Processes: ${PREFIX}_processes.log"echo " Events: ${PREFIX}_events.log"
# 快速汇总echo ""echo "=== Resource Summary ==="echo "Peak memory usage:"grep -v timestamp "${PREFIX}_cpu_mem.csv" | \ awk -F, '{avail=$7/1048576; if(max_used_mb=="") max_used_mb=($6-$7); if(($6-$7)>max_used_mb) max_used_mb=($6-$7)} END {printf " Max used: %.1f GB\n", max_used_mb/1048576}'echo "Min available memory:"grep -v timestamp "${PREFIX}_cpu_mem.csv" | \ awk -F, '{if(min_avail=="" || $7<min_avail) min_avail=$7} END {printf " Min avail: %.1f GB\n", min_avail/1048576}'这个脚本在流程运行时后台持续记录所有资源指标。跑完后打开 CSV 用 Excel/R 画个图,给导师汇报时还能附上”计算资源消耗分析”。
6. 踩坑记录
坑1:top 的 %MEM 包含了共享内存
症状:所有进程 %MEM 加起来远超 100%。
原因:top/ps 的 %MEM 基于 RSS(常驻内存),而多个进程共享的库(如 libc、libm)被重复计算。
# 更准确的物理内存占用:smem -t -k # 需要安装 smem# PSS (Proportional Set Size) 才是进程独有的内存坑2:free 看到 available 很大但进程报 OOM
症状:free -h 显示 100GB available,但程序还是 OOM 了。
原因:可能是 cgroup 限制(Docker/Slurm 等容器环境)。
# 检查 cgroup 限制cat /sys/fs/cgroup/memory/memory.limit_in_bytes# 如果是某个小于物理内存的值——找到罪魁祸首了坑3:ncdu 扫描 / 根目录耗时太久
症状:ncdu / 跑了 10 分钟还没完。
# 排除挂载的外部存储ncdu -x / # -x: 不跨越文件系统边界
# 或先快速找大目录du -h --max-depth=1 / 2>/dev/null | sort -rh | head -20# 然后再 ncdu 进那个大目录坑4:htop 里看不到所有 CPU 核心
症状:128 核的服务器,htop 只显示了几行 CPU 条。
在 htop 里按 F2 → Display options → 勾选 Detailed CPU time,或者用 htop -C 把每个核显示为竖条。
其实另一个更简单的选择:
# 显示所有核心的负载mpstat -P ALL 1坑5:iostat 的 %util 100% 不代表磁盘真满了
症状:NVMe SSD 上 %util 显示 100%,但实际吞吐远没到标称值。
原因:%util 反映的是”至少有一个 IO 请求在处理的时间占比”。对于能并发处理的 NVMe,100% 不一定意味着饱和。更应该看 await 和 aqu-sz。对于 NVMe:
坑6:du 和 df 显示不一致
症状:df 说磁盘满了,du 只统计出一半。
最常见原因:文件被删除但进程还持有文件句柄。
# 找出那些"幽灵"文件lsof +L1 | grep deleted# 或者lsof | grep '(deleted)'
# 重启持有这些句柄的进程就能释放空间坑7:nmon 记录数据但不能实时看
症状:nmon -f 只生成了文件,不知道怎么实时打开。
# 实时模式(不加 -f)nmon
# 或者让 nmon 同时记录和显示nmon -f -s 30 -c 2880 -m /opt/logs/ &nmon -r /opt/logs/server_*.nmon # 打开正在写的文件
# 还有:把 nmon 数据转成网页图表# nmonchart 可以把 .nmon 转成 .html7. 总结
| 监控目标 | 首选工具 | 一句话 |
|---|---|---|
| 谁吃了CPU | htop | 按F6排序CPU,F5看进程树 |
| 内存还剩多少 | free -h | 看available不是free |
| 谁在吃内存 | ps aux --sort=-%mem | 前5名 |
| 磁盘IO谁在跑 | sudo iotop -o | 一目了然 |
| 磁盘用满了没 | df -h; ncdu | df看全局, ncdu找元凶 |
| 长期趋势 | nmon -f | 跑完用nmonchart出图 |
| 文件被删但空间没释放 | lsof +L1 | 找deleted文件 |
监控不是一次性工作,把它嵌到每个流程脚本里去。多花 5 行 Bash 写监控,可能省下 5 小时的调试时间——这是我崩了三台服务器后悟出来的道理。
本文于 2025-11-10 在 Debian 12 服务器上实测。htop 3.3.0, iotop 1.26, nmon 16q, sysstat 12.7.6。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!