1 问题

今天查看服务器磁盘空间,发现磁盘占用达到了98%,所以看了一下日志文件目录的磁盘占用情况,发现有很多的sql日志文件很大,在10G以上,所以准备清理一下,一开始准备清理60天之前的日志,后来发现,清理完了,还是不行,磁盘空间还是占用98%,但是日志文件是真的被删了,今天分享一下这个事情的原因以及解决办法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//查看Linux整个系统的磁盘空间命令
$ df -h
Filesystem Size Used Avail Use% Mounted on
overlay 251G 10G 229G 5% /
tmpfs 64M 0 64M 0% /dev
tmpfs 993M 0 993M 0% /sys/fs/cgroup
shm 64M 0 64M 0% /dev/shm
//查看某个文件下所有文件的磁盘占用情况
$ du -sh *
0 log.20220627
40K log.20220707
48K log.20220708
8.0K log.20220707
4.0K log.20220627
244K log.20220707
828K log.20220708
//删除N天前的日志
$ find /data/logs -type f -name "*log*" -mtime +40 -exec rm {} \;

2 原因分析

在Linux上,每个文件都有一个自己对应的索引节点即inode,在这个inode里记录了文件在磁盘的块信息,以及链接数量等信息,一个文件在是否要被真正删除释放空间,取决于两个值,一个是i_count,代表引用计数;一个是i_nlink,代表硬链接数量,只有当两个都为0,文件才会真正释放。
当有进程使用该文件时候,i_count就会加1,当进程不在引用或进程结束,就会减一。

硬链接也是如此,当为文件创建一个硬链接时,i_nlink就会加一,删除就会减一,当减少为0时候,就会删除文件,释放空间。

可以通过以下命令查看文件被那些进程引用:

1
$ lsof | grep deleted

在Linux中,硬链接指的是文件名与inode的链接,通常创建一个文件对应一个硬链接,我们可以手动通过ln命令或者程序触发link系统调用为一个文件创建一个硬链接,相当于两个文件名对应了同一个磁盘文件,两个都删除才会删除磁盘文件(没有进程引用的前提下)。而Linux的rm命令相当于执行了unlink系统调用,会使得i_nlink数量减一。

当然,由于文件并没有被真正删除,所以该文件是可以恢复的,只需要找到进程的pid,并进入/proc/{pid}/fd中,找到对应的文件描述符,执行cp命令复制即可找回文件。

3 解决办法

3.1 杀进程

通过lsof命令查看被删除的文件的被那些进程所引用,然后kill掉这些进程即可,但是,这样做会有风险,如果这个进程是某个很重要的进程,那么会造成其他的问题,谨慎杀进程

3.2 文件重定向

使用如下命令将一个很大的日志文件的空间释放掉:

1
$ echo "" > log.log

注意:

  1. 这里需要注意,不要使用>>,两个尖括号是追加的意思,一个尖括号才是覆盖写入。
  2. 而且如果已经使用find /data/logs -type f -name "*log*" -mtime +40 -exec rm {} \;将某些文件删除了,那就只能等到对应进程释放该文件的资源了,不能再用这种方式释放空间,因为原来的文件已经不存在了,如果还使用该命令,则会重新创建一个新的文件,而原来的文件并没有释放

Reference

写在最后

欢迎大家关注鄙人的公众号【麦田里的守望者zhg】,让我们一起成长,谢谢。
微信公众号