5

Linux下删点日志也能搞死人

 3 years ago
source link: https://mp.weixin.qq.com/s/RyBjrjK378-yAUFAUcr-2A
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Linux下删点日志也能搞死人

Original felix021 felix021 7/6
收录于话题
#Linux 1236
#面试 3709
#字节跳动 890
Image

想了十天十夜不知道写些什么,那就写写面试题吧。


== 1 ==

在面试应聘者的时候,我常常会问:

在 Linux 下,如何删除一个目录下的所有 log 文件?

不知道是不是我人畜无害的围笑给了应聘者我很好应付的错觉

640?wx_fmt=png

以至于应聘者全都回答:rm *.log

追问:该目录下可能有很多子目录(还可能是多级),如何把子目录里的 log 文件也删掉呢?

答:rm -r *.log

640?wx_fmt=jpeg


== 2 ==

令我很意外的是,只有很少的应聘者能想到 find 命令。

而且想到的人也很少有记得具体用法的。

640?wx_fmt=jpeg

目前为止只有一个应聘者能够给出完整的命令:

find -name \*.log -exec rm -f {} \;

注:这里的两个斜杠都不是笔误。这里除了 -exec ...,也可以用 -delete,或者用管道结合 xargs 来完成;又或者 ls -r | grep 也行。

我觉得 find 应该不算一个很罕见的命令?

我们有一台共享开发机,因为大家都懒得删 log ,经常磁盘爆满,后来我们给它加了个 crontab:

0 4 * * * find /home/ -type f -name "*.log*" -size +100M -exec bash -c "echo -n > '{}'" \;

注:".log*" 后面的 * 是考虑了 log rotate。

注意,这个命令没有用 rm ,而是使用重定向来清空文件,原因后面会讲。


== 3 ==

基于清理磁盘空间这个场景,我还会继续问:

你有遇到过删了 log 文件,但是磁盘空间却没有释放的情况吗?

有些候选人可能心里在想着:文件删了不就删了吗,还有什么磁盘空间没释放?

640?wx_fmt=jpeg

所以有时候我需要解释一下,是 df 命令看到的磁盘空间没有减少。

还有个候选人努力想了想,和我确认,是不是正好这个目录挂载的是其他磁盘,所以看起来当前磁盘空间没减少。(当然不是)

思路稍微开阔一点的候选人会想到:你个憨批莫不是删了个软链接吧?

640?wx_fmt=jpeg

当然候选人的语气会比较友好。

然后我会和候选人继续沟通:

你提到了软链接,那它和硬链接的区别是什么呢?

有时候我怀疑这几个连续的问题问到候选人开始怀疑人生,因为有的候选人有点犹豫,觉得自己想说的其实是硬链接。

640?wx_fmt=jpeg

不过还是有几个候选人知道,软链接是一种文件类型,其内容是目标文件的路径;硬链接是 inode 的别名,同一个 inode 可以有多个链接,在 inode 里记录了硬链接的数量(引用计数)。

比如这样:

创建一个空文件,看下inode和链接数:

$ touch a.txt #创建一个空文件$ stat -c 'inode %i, links %h' a.txtinode 12058942, links 1

创建一个软链接,再看看文件大小:

$ ln -s a.txt b.txt #软链接$ stat -c 'inode %i, links %h' b.txtinode 12058978, links 1$ ls -l b.txt #大小5字节lrwxrwxrwx ... 5 ... b.txt -> a.txt$ readlink b.txt #文件内容a.txt

创建一个硬链接,看下inode和链接数

$ ln a.txt c.txt #硬链接,inode不变,链接数变成2$ stat -c 'inode %i, links %h' c.txtinode 12058942, links 2$ ls -l c.txt #大小0字节,和a一样lrwxrwxrwx ... 0 ... c.txt



== 4 ==

但实际生产上,遇到 “删了文件、但空间不释放” 通常和软/硬链接没有什么关系。

640?wx_fmt=png

实(cai)战(keng)经验比较丰富的候选人会知道,这更可能是因为文件正被另一个进程打开。

比如在终端 1 打开 a.txt:

$ python>>> f = open("a.txt")

然后在终端 2 可以看到该文件被 Python 打开:

$ lsof a.txtCOMMAND  PID ...     NODE NAMEpython  2390 ... 12058942 a.txt

删掉 a.txt,再查看 python 打开的文件列表:

$ rm a.txt$ ls -l /proc/2390/fdlrwx------ 1 user ... 00:04 0 -> /dev/pts/5lrwx------ 1 user ... 00:04 1 -> /dev/pts/5lrwx------ 1 user ... 00:04 2 -> /dev/pts/5lr-x------ 1 user ... 00:04 3 -> /tmp/a.txt (deleted)

注:0、1、2、3 是内核的 fd 编号。0=stdin, 1=stdout, 2=stder。

可以看到,a.txt  被标记为已删除,但因为进程还开着它,可能会访问文件的内容,所以内核会等到进程关闭该文件(或进程退出后)才在磁盘上移除这个文件。


== 5 ==

在面试中通常没有机会再问下去了,但实践中往往问题还没解决。

比如前述共享开发机,就曾遇到了用 df 看磁盘空间800G已满,但用 du 查看,所有文件却只占用了 500G的情况。

1. 如何才能知道现在系统中有哪些文件已删除、但是仍被占用呢?

$ sudo lsof | grep deletedCOMMAND   PID  …  NAMEmain   893246  …  /../nohup.out (deleted)...

发现是有大量已经被删除、但仍被某些进程打开的 nohup.out 。

2. 坑是找到了,该怎么填呢?

由于这是开发机,很简单,把进程杀掉就好了,进程退出时,内核会负责关闭文件,然后清理占用的空间。

但如果是线上服务呢?

Linux下有一个 package 叫 logrotate,像 nginx 这些服务就是使用它来做日志切割/轮转的。

但 nginx 是在后台持续运行的,不能为了切个日志就停止服务,所以它们是这样约定的:

  1. logrotate 执行 rename 系统调用(相当于 mv 命令)重命名日志文件;

  2. 由于 inode 不变,这时 nginx 会继续写入重命名后的日志文件;

  3. logrotate 给 nginx 发送一个 SIGHUP 信号;

  4. nginx 在收到信号后会关闭当前文件,并重新打开日志文件(即创建了新的日志文件)。

注:为什么是用 SIGHUP 而不是其他信号,以后可能会另开一篇讲讲。

这样 logrotate 出来的日志,就可以放心删除了。

对于不支持类似逻辑的服务怎么办呢?

重启大法。

如果只是想清空这个文件,可以这样(以前面python为例):

$ echo -n > /proc/2390/fd/3

这样文件是清空了,适用于 append only 的日志文件,但对于其他场景可能存在一定风险。

要是不怕背 P0 的话,还可以这么作死:

$ sudo gdb(gdb) attach $PID(gdb) call ftruncate(3, 0) #按需修改fd$1 = 0

注:ftruncate只是清空文件,如果想关闭文件,可以结合 dup、dup2、open和close来搞事,不细说了。

640?wx_fmt=jpeg


== 6 ==

看到这里你应该明白了为什么前面那个 find 命令不直接用 rm 了吧?

照例总结下:

  1. 可以用 find 查找文件

  2. 软链接存的是路径,硬链接共享inode

  3. 删除被进程打开的文件,磁盘空间不会释放

  4. lsof 很好用(不只是看文件的占用)

还想知道其他有意思的面试题吗?

不如投个简历来亲身体验下:

~ 投递链接 ~

投放研发工程师(上海)

https://job.toutiao.com/s/J8DRDyG

高级广告研发工程师(北京)

https://job.toutiao.com/s/J8DNwJY


640?wx_fmt=png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK