linux系统删除文件,不释放存储空间

一、问题现象:dudf的 “数据打架”

1. 环境与矛盾表现

  • 服务器:CentOS 7 系统,100G 数据盘挂载在 /data 目录
  • 现象:df -h 显示 /data 分区已用 100%,但 du -sh /data 仅统计到 30G 数据,两者相差 70G 左右
  • 排查:常规目录统计、文件查找均无异常,无法定位占用源

2. 关键线索:lsof 找到 “消失的空间”

  • 文件:/data/eyou/mail/log/mta.log(已被标记为 deleted
  • 进程:rsyslogd(日志服务),PID 为 18213,持有文件句柄 FD=3
  • 大小:约 60G,与 dfdu 的差值基本吻合

 

二、底层原理:为什么rm删了文件,空间却没释放?

1. Linux 文件系统的核心机制:硬链接与文件句柄

Linux 文件系统中,文件的存在依赖两个关键部分:
  1. inode:记录文件元数据(大小、权限、磁盘块位置)和硬链接计数
  2. 文件句柄(FD):进程打开文件时,内核会为进程分配一个文件描述符,指向该文件的 inode

2. rm 命令的真实作用:只删除目录项,不释放磁盘块

当你执行 rm /data/eyou/mail/log/mta.log 时,系统只做了两件事:
  • /data/eyou/mail/log/ 目录中,删除 mta.log 对应的目录项(文件名和 inode 的关联)
  • 将该文件 inode 的硬链接计数减 1
但此时,只要有进程仍持有该文件的文件句柄,inode 就不会被标记为可回收,磁盘上的实际数据块也不会被释放。du 命令只统计 “目录中存在的文件”,所以看不到这个 “已从目录中消失” 的文件;而 df 统计的是整个分区的磁盘块占用,所以能看到空间被占用。

三、> /proc/18213/fd/3 命令的底层逻辑

1. /proc 文件系统:进程与内核的 “交互窗口”

/proc 是 Linux 的虚拟文件系统,不占用实际磁盘空间,而是内核运行状态的 “镜像”。其中 /proc/[PID]/fd/ 目录下,会列出该进程所有打开的文件句柄:
  • /proc/18213/fd/3 代表进程 18213 打开的第 3 个文件句柄
  • 即使原文件已被 rm 删除,这个句柄依然指向磁盘上的原文件数据块

2. > 重定向:直接清空文件数据,不影响进程句柄

> /proc/18213/fd/3 命令的执行过程:
  1. 以写入模式打开文件句柄 /proc/18213/fd/3
  2. 将文件的大小截断为 0(清空所有数据块)
  3. 内核直接回收该文件占用的磁盘块,立刻释放空间
这种方式的优势在于:
  • 不需要重启进程,不会中断业务(rsyslogd 仍可正常写入日志)
  • 直接操作文件句柄,绕过了 “已删除目录项” 的限制,精准释放数据块

四、对比两种常见解决方案的优劣

方案 操作 原理 优点 缺点
句柄清空法 > /proc/[PID]/fd/[FD] 直接截断进程持有的文件句柄数据 无需重启服务,零业务中断,立刻释放空间 需要通过 lsof 定位 PID 和 FD
重启进程法 systemctl restart rsyslog 进程退出时,内核自动回收所有文件句柄 操作简单,无需手动定位句柄 会中断服务,可能导致日志丢失或业务短暂异常

五、问题根治与预防方案

1. 临时解决:清空句柄释放空间

# 1. 定位 PID 和 FD
lsof | grep deleted | grep mta.log

# 2. 清空句柄(替换 PID 和 FD 为实际值)
> /proc/18213/fd/3

# 3. 验证空间释放
df -h /data

2. 永久解决:配置日志轮转(logrotate)

/etc/logrotate.d/ 下创建 eyou-mail 配置文件,防止日志文件无限增长:
cat > /etc/logrotate.d/eyou-mail << EOF
/data/eyou/mail/log/mta.log {
    daily          # 按天轮转
    rotate 7       # 保留7天日志
    compress      # 轮转后压缩
    missingok     # 文件不存在时不报错
    notifempty    # 文件为空时不轮转
    create 0644 eyou eyou  # 新建文件的权限和属主
    postrotate
        systemctl reload rsyslog > /dev/null 2>&1 || true
    endscript
}
EOF

# 手动测试配置是否生效
logrotate -d /etc/logrotate.d/eyou-mail

3. 运维监控:定期检查 “幽灵文件”

将以下命令加入定时任务,每周自动检查一次:
# 检查已删除但未释放的文件
lsof | grep deleted | grep -v "/run/user" | awk '{print $1, $2, $NF}'

六、总结与避坑指南

  1. 核心原因rm 删除文件后,进程仍持有文件句柄,导致磁盘块无法释放,出现 dudf 数据不一致
  2. 快速修复> /proc/[PID]/fd/[FD] 是零业务中断的最优解,直接截断句柄数据释放空间
  3. 预防关键:不要直接 rm 业务日志文件,优先使用 > 文件名 清空或配置 logrotate 轮转
  4. 排查技巧:遇到 dudf 数据不一致时,优先用 lsof | grep deleted 检查 “幽灵文件”
阅读剩余
THE END