磁盘空间管理与清理:df/du/ncdu
生信数据量增长很快:一个样本的 fastq 10-30GB,比对完的 BAM 50-100GB,variant calling 中间文件可到 200GB。20 个样本就是好几个 TB。磁盘满了流程全崩——No space left on device 是高频报错。本文覆盖磁盘空间排查、大文件定位、缓存清理和自动化空间管理。
实测环境:Debian 12,80GB 系统盘 + 2TB 数据盘。
1. 查看磁盘使用——你的空间去哪了
1.1 df——看全局
# 人类可读格式df -h
# 只看特定分区df -h / /opt /home
# 显示文件系统类型df -hT输出示例:
Filesystem Size Used Avail Use% Mounted on/dev/sda1 79G 45G 30G 61% //dev/sdb1 2.0T 1.6T 400G 80% /data关注点:
Use%超过 80% 就要清理了Use%达到 100% 时所有写操作都会失败/dev/shm是内存盘(tmpfs),大小是物理内存的一半
1.2 du——看细节
# 当前目录下所有子目录的大小(汇总)du -sh */
# 按大小排序(最大的放最后)du -sh * | sort -h
# 显示深度1层du -h --max-depth=1 /opt/bioinfo
# 找出超过1GB的目录du -h --max-depth=2 /opt/bioinfo | grep 'G\b' | sort -hdu 会遍历所有文件计算大小,对大目录可能很慢。别在根目录直接 du /——可能跑半小时。
1.3 ncdu——交互式磁盘分析(强烈推荐)
sudo apt install ncdu -y
# 分析某个目录ncdu /opt/bioinfo
# 只分析,不进入交互模式(导出报告)ncdu -o disk_report.json /opt/bioinfo# 之后查看ncdu -f disk_report.jsonncdu 的交互界面里可以按 d 删除文件/目录,按 n 按文件名排序,按 s 按大小排序。比 du 直观 10 倍。我第一次用 ncdu 清理出了 300GB 的 conda 缓存和 pip 包,之前用 du 完全没发现。
2. 找大文件——定位罪魁祸首
2.1 find 找大文件
# 找出超过 1GB 的文件find /opt/bioinfo -type f -size +1G -exec ls -lh {} \; 2>/dev/null
# 找出最近 30 天没修改过的大文件(候选删除对象)find /opt/bioinfo -type f -size +1G -mtime +30 -exec ls -lh {} \;
# 找出最大的 10 个文件(不管在哪)find /opt/bioinfo -type f -exec du -h {} \; 2>/dev/null | sort -rh | head -10
# 更快的版本(用 du 配合 sort)du -ah /opt/bioinfo 2>/dev/null | sort -rh | head -202.2 生信特有大文件清单
| 文件类型 | 典型大小 | 能否删除 | 建议 |
|---|---|---|---|
| raw FASTQ (.fastq.gz) | 5-30GB/样本 | ❌ 原件 | 压缩后归档,多副本备份 |
| BAM 文件 | 50-100GB/样本 | ⚠️ 酌情 | 有 FASTQ 可重比对的话可删 |
| SAM 文件 | 200-500GB/样本 | ✅ | 转成 BAM 后立刻删 |
| 临时文件( /tmp/*) | 不定 | ✅ | 定期清理 |
| Conda 环境 | 2-10GB/环境 | ⚠️ | 导出 yml 后可重建 |
| conda pkgs 缓存 | 10-50GB | ✅ | conda clean -a |
| pip 缓存 | 1-5GB | ✅ | pip cache purge |
| Docker 镜像 | 5-20GB/镜像 | ⚠️ | docker system prune |
| 日志文件( .log) | 1-50GB | ⚠️ | 压缩旧 log,删调试级 log |
| 核心转储( core.*) | 1-50GB | ✅ | 程序崩溃的 dump,可删 |
3. 清理 Conda/Pip 缓存——生信最大的隐形空间杀手
Conda 下载的每个包都会缓存下来,日积月累能吃掉几十 GB。
# 看看缓存多大du -sh ~/miniconda3/pkgs/
# 清理所有缓存(包、索引、临时文件)conda clean --all -y
# 只清包缓存(下载的 .tar.bz2 文件)conda clean --packages -y
# 清理后确认du -sh ~/miniconda3/pkgs/pip 也有缓存:
# 查看缓存大小pip cache info
# 清理pip cache purge另外 Conda 每个环境都是一份完整的软件副本,10 个环境可能是 30-50GB:
# 查看所有环境的大小du -sh ~/miniconda3/envs/*/
# 删掉不用的环境conda env remove -n old_env_name
# 或者导出再删conda env export -n to_delete > to_delete.ymlconda env remove -n to_delete# 以后需要时 conda env create -f to_delete.yml4. 日志管理——设好轮转策略
生信流程会产生大量日志,pipeline.log 跑半年能到几十 GB。
4.1 手动轮转
# 压缩旧日志gzip old_log.log
# 只保留最近 N 行tail -n 100000 huge.log > trimmed.log
# 删掉超过 30 天的日志find /opt/bioinfo/logs -name "*.log" -mtime +30 -delete
# 更安全:先压缩再删find /opt/bioinfo/logs -name "*.log" -mtime +30 -exec gzip {} \;find /opt/bioinfo/logs -name "*.log.gz" -mtime +90 -delete4.2 logrotate——自动管理
/opt/bioinfo/logs/*.log { weekly rotate 4 compress missingok notifempty maxsize 500M}意思:每周轮转一次,保留 4 个历史版本,压缩旧日志,超过 500MB 强制轮转。
4.3 流程脚本里加日志限制
# 在 Shell 脚本里exec > >(tee logs/pipeline.log) 2>&1
# 跑完后截断# 只保留最后 50MBtail -c 50M logs/pipeline.log > logs/pipeline.log.trimmedmv logs/pipeline.log.trimmed logs/pipeline.log5. 临时文件清理——生信流程的垃圾场
5.1 /tmp 清理
很多生信工具(samtools sort、GATK、STAR)默认用 /tmp 做临时目录。进程崩溃后临时文件不会被删。
# 查看 /tmp 下的大文件du -sh /tmp/*/ 2>/dev/null | sort -rh | head -10
# 找几天前的遗留文件find /tmp -type f -mtime +3 -size +100M -exec ls -lh {} \;
# 谨慎清理(确保没有活进程在用)find /tmp -type f -mtime +3 -name "samtools*" -delete
# 更好的做法:给流程指定专用的临时目录TMPDIR=/opt/bioinfo/tmp samtools sort ...# 跑完流程手动清理 /opt/bioinfo/tmp5.2 中间文件管理
# 流程脚本里管道串联,避免产生中间文件# 坏:产生大量 SAM 文件bwa mem ref r1.fq r2.fq > sample.samsamtools sort sample.sam -o sample.bamrm sample.sam
# 好:管道一步到位bwa mem ref r1.fq r2.fq | samtools sort -o sample.bam -
# 批量删除中间文件find /opt/bioinfo/results -name "*.sam" -deletefind /opt/bioinfo/results -name "*.unsorted.bam" -delete5.3 用 trap 确保清理
#!/bin/bashset -euo pipefail
TMP_DIR=$(mktemp -d /opt/bioinfo/tmp/pipeline_XXXXXX)cleanup() { echo "Cleaning up temporary files..." rm -rf "$TMP_DIR"}trap cleanup EXIT
# 所有临时文件写到 $TMP_DIRsamtools sort -T "$TMP_DIR" -o output.bam input.sam# 脚本正常退出时自动清理,异常退出也会清理6. 软链接节省空间——一套参考基因组全组共享
参考基因组每个都几十 GB(含索引),5 个人每人拷一份就是 200GB。软链接解决这个问题:
# 公共目录放一份/opt/refs/hg38/hg38.fa/opt/refs/hg38/hg38.fa.bwt/opt/refs/hg38/hg38.fa.ann# ...
# 个人目录软链接过去ln -s /opt/refs/hg38 ~/refs/hg38
# 确认ls -la ~/refs/hg38# lrwxrwxrwx ... hg38 -> /opt/refs/hg38软链接不占额外空间(只占一个 inode 的大小),但使用上和真实目录一模一样。
7. 踩坑记录
坑1:df 显示磁盘满了,du 算出来却很小
症状:df -h 显示 100% 使用,但 du -sh / 算出来只有 50GB。
原因:有进程打开了某个大文件但已经被 rm 删了。文件虽然从目录里消失了,但进程还持有文件句柄,磁盘空间没有真正释放。
# 找出这种"已删除但仍被占用"的文件lsof +L1 | grep deleted# 或lsof | grep deleted | awk '{print $1, $2, $7}' | sort -rnk3 | head -10
# 解决方法:重启或 kill 持有文件句柄的进程kill PID这个坑在生信里极其常见——samtools sort 用的临时文件被 rm 了但进程还在跑,磁盘空间就是不释放。
坑2:ncdu 扫描根目录把 I/O 打满
症状:ncdu / 跑了 20 分钟,期间服务器响应极慢。
解决:
# 不要扫根目录,扫具体分区ncdu /opt # 而不是 ncdu /
# 或者先用 df 找到占用高的分区,再针对性分析df -hncdu /data # 如果 /data 分区满了坑3:conda clean —all 删了还需要的包
conda clean --all 会删掉所有不在当前环境里的包缓存。如果你只有一个环境那没事。如果有多个环境,某些包需要重新下载。
更安全的方式:
# 只删明确不需要的包缓存conda clean --packages --dry-run # 先看看会删什么conda clean --packages # 确认后执行坑4:rm 大文件后 df 没变化
跟前一个坑类似——文件被其他进程占着。确认:
# 删除前:检查有没有进程在用lsof /path/to/large/file
# 如果有进程在用,先停进程再删坑5:logrotate 配置了但没生效
症状:配了 /etc/logrotate.d/bioinfo,但日志还是在增长。
检查:
# 手动触发看看有没有报错logrotate -d /etc/logrotate.d/bioinfo # debug 模式logrotate -f /etc/logrotate.d/bioinfo # 强制执行
# 确认 cron 在跑systemctl status logrotate.timerDebian 上 logrotate 由 systemd timer 触发,不是 cron。确认 timer 是 active 状态。
坑6:find ... -delete 删错了
# 危险:这条命令递归删除所有 .log 文件find /opt -name "*.log" -delete
# 安全做法:先 list 确认,再删find /opt -name "*.log" -type f -size +1G# 确认无误后find /opt -name "*.log" -type f -size +1G -delete坑7:以为 df 的 Avail 可用就是真的可用
ext4 文件系统默认预留 5% 给 root 用户。普通用户看到的 Avail 扣掉了这 5%。所以有时候你发现还有几十 GB 空间但就是写不进去——因为你触达了普通用户的上限。
# 查看预留比例tune2fs -l /dev/sda1 | grep "Reserved block count"
# 数据盘可以降低这个预留比(不要对系统盘做)sudo tune2fs -m 1 /dev/sdb1 # 降到1%8. 小结
| 操作 | 命令 | 频率建议 |
|---|---|---|
| 全局查看 | df -h | 每天 |
| 交互分析 | ncdu /data | 每周 |
| 找大文件 | find /data -size +1G | 每周 |
| 清 conda 缓存 | conda clean --all | 每月 |
| 清 pip 缓存 | pip cache purge | 每月 |
| 旧日志压缩 | find logs -mtime +30 -exec gzip {} \; | 每月 |
| 清 /tmp | find /tmp -mtime +3 -delete | 每周 |
| lsof 查泄露 | lsof +L1 | 出问题时 |
磁盘管理是个习惯问题。我现在的习惯:每周一早上 df -h 看一眼,ncdu 扫一遍数据分区,发现异常立刻处理。养成这个习惯需要 5 分钟,但能避免凌晨 3 点被”磁盘满了流程挂了”的告警叫醒。
本文于 2025-07-30 在 Debian 12 上实测完成。ncdu 2.3,conda 24.11.0,所有命令可直接使用。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!