问题:Linux文件删除,但是df之后磁盘空间没有释放
Linux 磁盘空间报警,查到到大文件,删除之后,df看到磁盘空间并没有释放。
通过查找发现,系统对rm命令进行了alias,类似windows的回收站功能,对删除的文件进行自定易操作(移动到/temp
中)。
对/temp中的文件进行删除,但是df -h
命令查看,空间还是为得到释放。
所以执行lsof | grep deleted
查看,发现有写文件虽然已经删除,但是文件还是没有真正得到释放,还被一些线程占用,进行读写操作。kill掉进程或者重启系统。
这是在df -h
,系统成功释放。
操作过程
1. 发现错误
因为项目需求,需要往项目所用的数据中添加一些字段,在执行sql的时候,系统报错(postgresql No space left on device),项目使用pgsql;于是登陆系统,查看磁盘空间。
这里说一些服务器的删除策略,由于Linux系统没有回收站。公司为了确保错误删除的文件能够恢复,所以重写了rm
命令;将删除的文件先移动到/temp
文件夹下,然后再定期清理/temp
下的文件,来达到模拟windows的回收站功能;
这个策略并没有什么问题,一般都会使用这个策略,但是公司的/temp
文件夹并没有单独划分空间,所以/temp
占用的还是系统内存。
执行命令发现/temp
存在大文件。
[root@localhost~ ]# du -s /tmp/*|sort -nr|head -3
36206016 /tmp/access_log
我们通过命令可以看出,这个文件大概占用了35G左右的空间,应该是很久没有清理过的文件啦。那么我们先删除这个文件。
我们再看一下空间是否已经释放:
这是什么鬼,空间还是没有释放。
2、解决思路
一般说来不会出现删除文件后空间不释放的情况,但是也存在例外,比如文件被进程锁定,或者有进程一直在向这个文件写数据等等,要理解这个问题,就需要知道Linux下文件的存储机制和存储结构。
一个文件在文件系统中的存放分为两个部分:数据部分和指针部分,指针位于文件系统的meta-data中,数据被删除后,这个指针就从meta-data中清除了,而数据部分存储在磁盘中,数据对应的指针从meta-data中清除后,文件数据部分占用的空间就可以被覆盖并写入新的内容,之所以出现删除access_log文件后,空间还没释放,就是因为httpd进程还在一直向这个文件写入内容,导致虽然删除了access_log文件,但文件对应的指针部分由于进程锁定,并未从meta-data中清除,而由于指针并未被删除,那么系统内核就认为文件并未被删除,因此通过df命令查询空间并未释放也就不足为奇了。
3、问题排查
既然有了解决问题的思路,那么接下来看看是否有进程一直在向acess.log文件中写数据,这里需要用到Linux下的lsof命令,通过这个命令可以获取一个已经被删除但仍然被应用程序占用的文件列表,命令执行如下图所示:
从输出结果可以看到,/tmp/acess.log文件被进程httpd锁定,而httpd进程还一直向这个文件写入日志数据,从第七列可知,这个日志文件大小仅70G,而系统根分区总大小才100G,由此可知,这个文件就是导致系统根分区空间耗尽的罪魁祸首,在最后一列的“deleted”状态,说明这个日志文件已经被删除,但由于进程还在一直向此文件写入数据,空间并未释放。
4、解决问题
到这里问题就基本排查清楚了,解决这一类问题的方法有很多种,最简单的方法是关闭或者重启httpd进程,当然也可以重启操作系统,不过这并不是最好的方法,对待这种进程不停对文件写日志的操作,要释放文件占用的磁盘空间,最好的方法是在线清空这个文件,可以通过如下命令完成:
[root@localhost ~]# echo " " >/tmp/acess.log
通过这种方法,磁盘空间不但可以马上释放,也可保障进程继续向文件写入日志,这种方法经常用于在线清理Apache、Tomcat、Nginx等Web服务产生的日志文件。