在进行采集日志时,日志文件明明被滚动压缩并转移走了,但是发现磁盘空间还是在不断增长,统一目录下的总文件大小,发现与实际占用也不符,于是想到可能是文件句柄未释放导致的,本文就来记录一下文件及文件句柄查看相关的内容,方便查阅。
在 linux 中,一切皆文件,我们最熟悉的创建目录,创建文件,查看文件
mkdir test_dir
cd test_dir
touch test.log
ls -al
而对于文件来说,实际上是一个指向inode的链接, inode链接包含了文件的所有属性, 比如权限和所有者, 数据块地址(文件存储在磁盘的这些数据块中)。
当你删除(rm)一个文件时, 实际删除了指向inode的链接, 并没有删除inode的内容, 进程可能还在使用,只有当inode的所有链接完全删除后, 然后这些数据块才可以写入新的数据。
所谓的指向inode的链接,其实就是指 fd 文件描述符,我们来实际操作一下,理解一下上面的概念
如何查看文件的 inode 呢? ls 的 -i
参数可以查看文件的 inode 编号
ls -ali
total 8
1970254 drwxr-xr-x 2 root root 4096 Oct 18 16:03 .
2097155 drwx------ 1 root root 4096 Oct 18 16:03 ..
1970255 -rw-r--r-- 1 root root 0 Oct 18 16:03 test.log
其中第一列就是 inode 编号
我们在进行 mv 操作时,虽然文件名改变了,但是 inode 是不变的,你可以仅仅认为名称是一个软连接一样,文件本质不变
mv test test1.log
ls -ali
通常情况下,我们直接使用 rm 命令就可以删除文件,但是如果遇到一些特殊字符(控制字符,乱码字符)之类的文件,键盘都打不出来,怎么办呢?这时候可以通过 find 配合 inode num 来删除文件。
find ./ -inum 1970255 -delete
终于来到了开头提到遇到的问题了,有时候我们发现了文件,但是空间并没有释放的问题,这个问题的原因就是文件句柄还在被进程占用导致的,我们来模拟一下。
touch a.log
echo aa > a.log
# 使用 tail 命令保持对 a.log 的监听
tail -f a.log
再打开一个终端窗口,删掉 a.log, 然后通过 lsof 命令查看文件句柄占用情况。
rm a.log
# 找到 tail 的进程号
ps -ef | grep tail
# 查看文件句柄的占用情况
lsof -p 7414
发现有一个 deleted 标识的 fd 占用,当前目录下已经没有 a.log 文件了,但是其实这个文件还没有释放。
查看进程打开的描述符,确实 tail 进程还占用着
# ls -al /proc/{进程ID}/fd/ 查看进程打开的 fd
ls -al /proc/7414/fd/
这时唯一的解决办法就是将 tail 进程关掉,这个文件才会被真正的删掉
ctrl + c
终止掉 tail 命令,再来查看
ls -al /proc/7414/fd/
lsof -p 7414
分享一个查看进程占用 fd 排行的小指令, 第一列表示 fd 打开数,第二列是进程ID
lsof -n | awk '{print $2}' | sort | uniq -c | sort -nr
这里的文件恢复是指 fd 还没释放,只是通过 rm 删掉的文件的恢复,其实也比较简单,将进程 fd 对应的文件再 copy 出来就可以了。
终端1的相关操作
终端2的相关操作
关键步骤就是标号 ④
cp /proc/7530/fd/3 aa.log
本次的分享到此结束,希望对你有所帮助。
如果你对我分享的内容感兴趣,欢迎扫码关注公众号:新质程序猿,并设置星标,推送更实时哟!