磁盘空间管理与清理:df/du/ncdu

2364 字
12 分钟
磁盘空间管理与清理: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——看全局#

Terminal window
# 人类可读格式
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——看细节#

Terminal window
# 当前目录下所有子目录的大小(汇总)
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 -h

du 会遍历所有文件计算大小,对大目录可能很慢。别在根目录直接 du /——可能跑半小时。

1.3 ncdu——交互式磁盘分析(强烈推荐)#

Terminal window
sudo apt install ncdu -y
# 分析某个目录
ncdu /opt/bioinfo
# 只分析,不进入交互模式(导出报告)
ncdu -o disk_report.json /opt/bioinfo
# 之后查看
ncdu -f disk_report.json

ncdu 的交互界面里可以按 d 删除文件/目录,按 n 按文件名排序,按 s 按大小排序。比 du 直观 10 倍。我第一次用 ncdu 清理出了 300GB 的 conda 缓存和 pip 包,之前用 du 完全没发现。

2. 找大文件——定位罪魁祸首#

2.1 find 找大文件#

Terminal window
# 找出超过 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 -20

2.2 生信特有大文件清单#

文件类型典型大小能否删除建议
raw FASTQ (.fastq.gz)5-30GB/样本❌ 原件压缩后归档,多副本备份
BAM 文件50-100GB/样本⚠️ 酌情有 FASTQ 可重比对的话可删
SAM 文件200-500GB/样本转成 BAM 后立刻删
临时文件( /tmp/*)不定定期清理
Conda 环境2-10GB/环境⚠️导出 yml 后可重建
conda pkgs 缓存10-50GBconda clean -a
pip 缓存1-5GBpip cache purge
Docker 镜像5-20GB/镜像⚠️docker system prune
日志文件( .log)1-50GB⚠️压缩旧 log,删调试级 log
核心转储( core.*)1-50GB程序崩溃的 dump,可删

3. 清理 Conda/Pip 缓存——生信最大的隐形空间杀手#

Conda 下载的每个包都会缓存下来,日积月累能吃掉几十 GB。

Terminal window
# 看看缓存多大
du -sh ~/miniconda3/pkgs/
# 清理所有缓存(包、索引、临时文件)
conda clean --all -y
# 只清包缓存(下载的 .tar.bz2 文件)
conda clean --packages -y
# 清理后确认
du -sh ~/miniconda3/pkgs/

pip 也有缓存:

Terminal window
# 查看缓存大小
pip cache info
# 清理
pip cache purge

另外 Conda 每个环境都是一份完整的软件副本,10 个环境可能是 30-50GB:

Terminal window
# 查看所有环境的大小
du -sh ~/miniconda3/envs/*/
# 删掉不用的环境
conda env remove -n old_env_name
# 或者导出再删
conda env export -n to_delete > to_delete.yml
conda env remove -n to_delete
# 以后需要时 conda env create -f to_delete.yml

4. 日志管理——设好轮转策略#

生信流程会产生大量日志,pipeline.log 跑半年能到几十 GB。

4.1 手动轮转#

Terminal window
# 压缩旧日志
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 -delete

4.2 logrotate——自动管理#

/etc/logrotate.d/bioinfo
/opt/bioinfo/logs/*.log {
weekly
rotate 4
compress
missingok
notifempty
maxsize 500M
}

意思:每周轮转一次,保留 4 个历史版本,压缩旧日志,超过 500MB 强制轮转。

4.3 流程脚本里加日志限制#

Terminal window
# 在 Shell 脚本里
exec > >(tee logs/pipeline.log) 2>&1
# 跑完后截断
# 只保留最后 50MB
tail -c 50M logs/pipeline.log > logs/pipeline.log.trimmed
mv logs/pipeline.log.trimmed logs/pipeline.log

5. 临时文件清理——生信流程的垃圾场#

5.1 /tmp 清理#

很多生信工具(samtools sort、GATK、STAR)默认用 /tmp 做临时目录。进程崩溃后临时文件不会被删。

Terminal window
# 查看 /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/tmp

5.2 中间文件管理#

Terminal window
# 流程脚本里管道串联,避免产生中间文件
# 坏:产生大量 SAM 文件
bwa mem ref r1.fq r2.fq > sample.sam
samtools sort sample.sam -o sample.bam
rm sample.sam
# 好:管道一步到位
bwa mem ref r1.fq r2.fq | samtools sort -o sample.bam -
# 批量删除中间文件
find /opt/bioinfo/results -name "*.sam" -delete
find /opt/bioinfo/results -name "*.unsorted.bam" -delete

5.3 用 trap 确保清理#

#!/bin/bash
set -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_DIR
samtools sort -T "$TMP_DIR" -o output.bam input.sam
# 脚本正常退出时自动清理,异常退出也会清理

6. 软链接节省空间——一套参考基因组全组共享#

参考基因组每个都几十 GB(含索引),5 个人每人拷一份就是 200GB。软链接解决这个问题:

Terminal window
# 公共目录放一份
/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 删了。文件虽然从目录里消失了,但进程还持有文件句柄,磁盘空间没有真正释放。

Terminal window
# 找出这种"已删除但仍被占用"的文件
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 分钟,期间服务器响应极慢。

解决:

Terminal window
# 不要扫根目录,扫具体分区
ncdu /opt # 而不是 ncdu /
# 或者先用 df 找到占用高的分区,再针对性分析
df -h
ncdu /data # 如果 /data 分区满了

坑3:conda clean —all 删了还需要的包#

conda clean --all 会删掉所有不在当前环境里的包缓存。如果你只有一个环境那没事。如果有多个环境,某些包需要重新下载。

更安全的方式:

Terminal window
# 只删明确不需要的包缓存
conda clean --packages --dry-run # 先看看会删什么
conda clean --packages # 确认后执行

坑4:rm 大文件后 df 没变化#

跟前一个坑类似——文件被其他进程占着。确认:

Terminal window
# 删除前:检查有没有进程在用
lsof /path/to/large/file
# 如果有进程在用,先停进程再删

坑5:logrotate 配置了但没生效#

症状:配了 /etc/logrotate.d/bioinfo,但日志还是在增长。

检查:

Terminal window
# 手动触发看看有没有报错
logrotate -d /etc/logrotate.d/bioinfo # debug 模式
logrotate -f /etc/logrotate.d/bioinfo # 强制执行
# 确认 cron 在跑
systemctl status logrotate.timer

Debian 上 logrotate 由 systemd timer 触发,不是 cron。确认 timer 是 active 状态。

坑6:find ... -delete 删错了#

Terminal window
# 危险:这条命令递归删除所有 .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 空间但就是写不进去——因为你触达了普通用户的上限。

Terminal window
# 查看预留比例
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 {} \;每月
清 /tmpfind /tmp -mtime +3 -delete每周
lsof 查泄露lsof +L1出问题时

磁盘管理是个习惯问题。我现在的习惯:每周一早上 df -h 看一眼,ncdu 扫一遍数据分区,发现异常立刻处理。养成这个习惯需要 5 分钟,但能避免凌晨 3 点被”磁盘满了流程挂了”的告警叫醒。


本文于 2025-07-30 在 Debian 12 上实测完成。ncdu 2.3,conda 24.11.0,所有命令可直接使用。

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

磁盘空间管理与清理:df/du/ncdu
https://fg.ink/posts/disk-space-management/
作者
风观
发布于
2024-03-15
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
风观
风有来路,观有所思
分类
标签
站点统计
文章
50
分类
1
标签
29
总字数
61,837
运行时长
0
最后活动
0 天前

文章目录