服务器磁盘快满了,删除几个大日志文件后,执行 df -h 却发现可用空间几乎没有变化,这是怎么回事?
一种常见原因是:文件名已经删除,但程序仍然打开着这个文件。 程序甚至可能继续向其中写入数据,因此目录中看不到文件,磁盘空间却仍被占用。
下面介绍具体排查和处理步骤。
1. 确认删除文件所在的文件系统
以清理 /var/log 下的日志为例,先执行:
df -hT /var/log
重点查看:
| 字段 | 含义 |
|---|---|
| Filesystem | 文件系统对应的设备 |
| Type | 文件系统类型 |
| Used | 已用空间 |
| Avail | 可用空间 |
| Use% | 空间使用率 |
| Mounted on | 挂载点 |
如果结果显示挂载点是 /,说明该目录使用根文件系统。此时可以统计同一文件系统中可见文件的占用:
sudo du -shx /
其中,-x 表示不跨越到其他文件系统。若实际挂载点是 /data,应改为统计 /data,不要拿某个小目录的占用与整个分区直接比较。
目录较大时,du 可能运行较久,避免反复扫描。
还可以检查inode使用情况:
df -i /var/log
如果 IUse% 接近100%,可能是大量小文件耗尽了inode,需要进一步排查文件数量。
需要注意,df 统计文件系统整体空间,du 统计目录树中的文件占用,两者不一定完全相等。明显差异可以作为排查线索,但不能单凭差值认定原因。

2. 查找已删除但仍被打开的文件
执行:
sudo lsof -nP +L1
如果提示找不到 lsof,先通过当前系统的包管理器安装该工具。
参数含义:
-
-n:不将IP地址转换成主机名。 -
-P:不将端口号转换成服务名。 -
+L1:筛选链接数小于1的已打开文件。
重点查看以下字段:
| 字段 | 排查用途 |
|---|---|
| COMMAND | 打开文件的进程名称 |
| PID | 进程编号 |
| FD | 文件描述符及访问方式 |
| TYPE | 文件类型,普通文件通常显示REG |
| SIZE/OFF | 文件大小或偏移量,具体含义取决于文件类型 |
| NLINK | 链接数,0表示已经没有目录链接 |
| NAME | 文件路径,可能带有(deleted)标记 |
例如,发现某个Nginx进程仍打开着:
/var/log/nginx/access.log (deleted)
同时 NLINK 为0、文件体积较大,就应继续核对它是否属于空间紧张的文件系统。
出现已删除文件并不一定代表故障。 一些程序会正常使用“创建后立即删除、继续保持打开”的临时文件,需要结合文件大小、所在设备和业务用途判断。
同一个文件还可能被多个进程同时打开。不能把每行的大小直接相加,否则会重复计算;可结合 DEVICE 和 NODE 判断是否为同一个文件。

3. 确认进程属于哪个服务
假设查到的进程编号为2468,可以执行:
ps -p 2468 -o pid,ppid,user,args
查看进程所属用户、父进程和启动命令。
在使用systemd的系统中,还可以执行:
sudo systemctl status 2468 --no-pager
该命令可帮助定位包含此进程的服务单元。
也可以只检查这个进程打开的已删除文件:
sudo lsof -nP -a -p 2468 +L1
这里的 -a 用于同时应用PID和链接数筛选条件。请将2468替换成实际查到的PID。
如果进程属于Docker容器,应继续确认对应容器及应用。容器内外的PID和可见文件范围可能不同,不能仅凭进程名称随意重启。
4. 让程序关闭旧文件
处理方式取决于文件用途和程序支持的操作。
Nginx日志:重新打开日志文件
如果确认被占用的是Nginx访问日志或错误日志,可使用:
sudo nginx -s reopen
该操作会通知Nginx重新打开日志文件。成功后,相关进程关闭旧日志的文件描述符,并转向新的日志文件。
执行时应使用当前实例对应的Nginx程序及配置。面板安装、自定义路径、多实例或容器部署环境,不能默认系统中的 nginx 命令就对应目标实例。
若提示PID文件不存在、权限不足或无法打开日志,应先处理具体错误,再检查释放结果。
其他应用:按程序支持的方式处理
优先查看应用是否支持重新打开日志或主动关闭相关文件。不同程序对重载配置和信号的处理不同,不能把Nginx的方法直接套用到所有服务。
如果应用没有相应机制,可以在确认业务影响后,通过服务管理工具正常重启对应服务。例如:
sudo systemctl restart myapp.service
myapp.service 只是示例,必须替换为已经确认的真实服务名。重启可能中断正在处理的请求,应选择合适时机操作。
不要根据PID批量强制结束进程,也不要直接清空未知的 /proc/PID/fd/编号。如果文件实际属于数据库或业务数据,错误处理可能造成数据损坏。
5. 验证空间和业务是否恢复
处理后重新检查:
sudo lsof -nP +L1
df -hT /var/log
重点确认:
-
目标文件不再出现在已删除但仍打开的文件列表中。
-
同一文件的其他持有进程也已关闭对应文件。
-
目标文件系统的可用空间有所增加。
-
网站、接口或应用服务运行正常。
-
新日志文件能够正常生成并继续记录。
例如,检查Nginx访问日志:
sudo ls -lh /var/log/nginx/access.log
访问一次网站后,再观察日志是否更新。路径应以实际Nginx配置为准。
如果没有查到目标文件,还要确认查询过程中没有权限或读取错误。磁盘空间仍未恢复时,应继续检查是否看错了分区、是否还有其他持有进程,以及应用是否正在快速生成新数据。

6. 配置日志轮转,减少重复发生
直接删除正在写入的大日志,容易留下仍被程序占用的旧文件。建议使用应用自带的日志管理功能或 logrotate,根据业务设置:
-
日志保留天数或份数。
-
单个日志文件的轮转条件。
-
历史日志压缩策略。
-
轮转后重新打开日志的操作。
配置完成后,应观察一次实际轮转过程,确认旧文件可以释放、新日志持续写入。
同时监控磁盘空间和inode使用率,预留处理时间,避免等到文件系统完全写满后再清理。
常见问题
为什么目录里找不到文件,程序还可以继续写入?
删除操作移除了文件在目录中的名称。对于已经打开的文件,程序仍可通过文件描述符访问它。文件没有其他硬链接,且相关打开引用全部释放后,占用的空间才能被回收。
执行sync能释放这类空间吗?
sync 用于将缓存中的修改写入存储设备,不会要求应用关闭文件,因此不能解决“已删除文件仍被进程打开”的问题。
必须重启整台服务器吗?
通常可以先处理持有文件的应用。支持日志重开的服务可使用对应功能;其他情况再评估是否需要正常重启该服务。
注意事项
操作前确认目标文件、进程和业务用途。对于数据库文件、业务数据或需要保留的日志,应先确认备份与恢复需求,再进行处理。
使用莱卡云服务器时,如需协助排查,可向莱卡云技术支持提供磁盘使用情况、删除文件的时间与路径,以及脱敏后的 lsof 和进程查询结果,便于定位空间未释放的原因。