Linux根分区爆满(占用81%)排查与解决实战
在Linux服务器运维过程中,根分区爆满是非常常见的紧急故障,若不及时处理,会导致服务器无法正常运行、服务卡顿甚至崩溃。本文以本人(Java技术人员)的视角,记录一次CentOS服务器根分区占用81%的完整排查、定位与解决过程——运维同事先告知服务器磁盘空间报警,且已自行删除对应的大文件,但未将删除操作及后续情况通知我,导致我排查时出现诸多异常,全程实操可复现,适合Java技术人员、运维新手参考学习。
一、故障现象
登录服务器后,执行常规磁盘空间查询命令 df -h,发现根分区(/)异常:
[root@localhost /]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 7.8G 0 7.8G 0% /dev
tmpfs 7.8G 0 7.8G 0% /dev/shm
tmpfs 7.8G 161M 7.6G 3% /run
tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 41G 9.7G 81% /
/dev/sda1 1014M 150M 865M 15% /boot
/dev/mapper/centos-home 42G 699M 41G 2% /home
tmpfs 1.6G 0 1.6G 0% /run/user/0
根分区总大小50G,已使用41G,使用率达81%,剩余空间不足10G,随时可能爆满。按照常规思路,先排查根目录下各文件夹的占用情况,定位大文件。
二、初步排查:定位根目录大文件夹
切换到根目录(cd /),执行命令查询所有一级目录的占用大小,并按从大到小排序:
[root@localhost /]# du -sh * | sort -hr
执行结果出现异常:所有目录占用大小相加不足4G,与df -h显示的41G已用空间严重不符,且出现部分无法访问的提示(proc目录相关,属正常现象):
du: cannot access ‘proc/25935/task/25935/fd/4’: No such file or directory
du: cannot access ‘proc/25935/task/25935/fdinfo/4’: No such file or directory
1.9G usr
667M home
640M var
334M opt
161M run
147M root
118M boot
32M etc
68K tmp
0 sys
0 srv
0 sbin
0 proc
0 mnt
0 media
0 lib64
0 lib
0 dev
0 bin
三、关键定位:找到“隐形”占用文件
排查到这里陷入疑惑:所有目录占用相加不足4G,与df -h显示的41G已用空间严重不符,后续与运维同事沟通后才得知,运维同事在告知我磁盘空间报警后,已自行删除了服务器上的大文件(即后续定位到的nohup.out文件),但未及时通知我这一操作,也未检查该大文件对应的Java进程是否释放文件句柄。结合运维经验,这种“du与df结果不一致”的情况,大概率是 文件已被删除,但对应的进程仍在占用该文件,导致磁盘空间未释放。被删除的文件此时会变成“隐形文件”,常规查询无法发现,但会持续占用磁盘空间,这也解释了为什么运维同事删除大文件后,磁盘占用依然居高不下,且我排查时会出现“目录占用与磁盘已用严重不匹配”的异常。
执行以下命令,查找所有被删除但仍被进程占用的文件:
[root@localhost /]# lsof | grep deleted
执行结果瞬间定位到元凶:一个Java进程(PID为26192)占用了一个已删除的nohup.out文件,该文件大小高达37.8G,正是导致根分区爆满的核心原因!同时还有zabbix-agent进程占用少量已删除文件(影响可忽略)。
核心异常输出片段:
java 26192 root 1w REG 253,0 37889443145 34805216 /opt/unionpay/nohup.out (deleted)
java 26192 root 2w REG 253,0 37889443145 34805216 /opt/unionpay/nohup.out (deleted)
补充说明:lsof 命令用于查看进程打开的文件,grep deleted 筛选出已被删除但仍被进程占用的文件;输出中“37889443145”即为文件大小(约35.3G),“26192”是占用该文件的Java进程PID,“1w”“2w”表示进程的标准输出(stdout)和标准错误(stderr)仍指向该文件。
四、解决方案:释放空间(无需重启Java进程)
对于这种“进程占用已删除文件”的场景,有两种解决方式:
- 重启占用文件的进程:简单直接,但会导致服务中断(不适合生产环境核心服务);
- 清空进程占用的文件描述符:无需重启进程,瞬间释放空间,适合生产环境。
本次采用第二种方式,针对Java进程(PID=26192)的文件描述符(1和2,对应stdout和stderr)执行清空操作:
[root@localhost /]# > /proc/26192/fd/1
[root@localhost /]# > /proc/26192/fd/2
命令说明:/proc/[PID]/fd/ 目录下存放着进程打开的所有文件描述符,“1”对应标准输出,“2”对应标准错误;> 符号表示清空文件内容(而非删除文件),执行后会立即释放该文件占用的磁盘空间。
执行完成后,再次执行 df -h 验证,根分区使用率已降至正常水平(约8%),空间释放成功。
五、补充优化:处理次要占用与避免复发
1. 清理zabbix-agent占用的已删除文件
除Java进程外,zabbix-agent进程也占用了少量已删除文件(日志和PID文件),虽不影响磁盘空间,但为了系统整洁,重启zabbix-agent服务即可释放:
[root@localhost /]# systemctl restart zabbix-agent
2. 避免后续再出现类似问题
本次故障的根源是:运维同事告知我服务器磁盘空间报警后,自行删除了持续增大的nohup.out大文件,但未通知我这一操作,也未检查该文件对应的Java进程是否释放文件句柄;同时,最初使用nohup启动Java服务时,未处理输出日志,导致nohup.out文件持续增大,多重因素叠加,最终导致磁盘爆满。针对此问题,给出两个优化方案,同时规范团队沟通与操作流程:
- 丢弃
nohup输出(推荐,无需日志时):nohup java -jar xxx.jar > /dev/null 2>&1& 说明:/dev/null表示丢弃输出,2>&1表示将标准错误重定向到标准输出,最终所有输出都被丢弃,不会生成nohup.out文件。 - 配置日志轮转(需要保留日志时): 使用
logrotate工具对nohup.out或Java应用日志进行轮转,设置日志大小限制、保留天数,避免日志无限增大。
六、总结与复盘
本次故障排查核心逻辑:df -h 发现磁盘爆满 → du -sh * 排查目录占用,发现异常(大小不匹配) → lsof | grep deleted 定位进程占用的已删除文件 → 清空文件描述符释放空间 → 优化配置避免复发。
关键知识点:
df查看磁盘分区整体使用情况,du查看目录/文件具体占用大小,两者结果不一致时,优先考虑“进程占用已删除文件”;lsof | grep deleted是定位此类问题的核心命令,可快速找到隐形占用文件;- 生产环境中,避免直接重启核心服务,优先使用“清空文件描述符”的方式释放空间,减少服务中断风险。
通过本次排查,不仅解决了磁盘爆满问题,还掌握了“进程占用已删除文件”的排查技巧,同时也提醒团队:运维操作需规范、沟通需及时——运维同事执行删除大文件等关键操作后,需及时通知相关技术人员(如Java开发/技术人员),且必须检查对应进程是否释放文件句柄,避免其他人员排查时出现困惑;后续可通过规范日志管理、明确团队沟通与操作流程,彻底避免此类故障再次发生。