Linux下刪點日誌也能搞死人

rm.png

想了十天十夜不知道寫些什麼,那就寫寫面試題吧。node

1

在面試應聘者的時候,我經常會問:python

在 Linux 下,如何刪除一個目錄下的全部 log 文件?nginx

不知道是否是我人畜無害的圍笑給了應聘者我很好應付的錯覺 面試

王寶強.png

以致於應聘者全都回答:rm *.logbash

追問:該目錄下可能有不少子目錄,如何把子目錄裏的 log 文件也刪掉呢?spa

答:rm -r *.log 3d

一臉人畜無害的笑容.jpeg

2

令我很意外的是,真的只有不多的應聘者能想到 find 命令。日誌

並且想到的人也不多有記得具體用法的。code

周星馳.png

目前爲止只有一個應聘者可以給出完整的命令:blog

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

注:這裏的兩個斜槓都不是筆誤。

我以爲 find 應該不算一個很罕見的命令?

咱們有一臺共享開發機,由於你們都懶得刪 log ,常常磁盤爆滿,後來咱們給它加了個 crontab:

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

注:".log*" 後面的 * 是考慮了 log rotate。

注意,這個命令沒有用 rm ,而是使用重定向來清空文件,緣由後面會講。

3

基於清理磁盤空間這個場景,我還會繼續問:

你有遇到過刪了 log 文件,可是磁盤空間卻沒有釋放的狀況嗎?

有些候選人可能內心在想着:文件刪了不就刪了嗎,還有什麼磁盤空間沒釋放?

微笑中透漏着.jpeg

因此有時候我須要解釋一下,是 df 命令看到的磁盤空間沒有減小。

還有個候選人努力想了想,和我確認,是否是正好這個目錄掛載的是其餘磁盤,因此看起來當前磁盤空間沒減小。(固然不是)

思路稍微開闊一點的候選人會想到:你個憨批莫不是刪了個軟連接吧?

華而不實的腦子.png

固然候選人的語氣會比較友好。

而後我會和候選人繼續溝通:

你提到了軟連接,那它和硬連接的區別是什麼呢?

有時候我懷疑這幾個連續的問題問到候選人開始懷疑人生,由於有的候選人有點猶豫,以爲本身想說的實際上是硬連接。

反正我信了.png

不過仍是有幾個候選人知道,軟連接是一種文件類型,其內容是目標文件的路徑;硬連接是 inode 的別名,同一個 inode 能夠有多個連接,在 inode 裏記錄了硬連接的數量(引用計數)。

好比這樣:

建立一個空文件,看下inode和連接數:

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

建立一個軟連接,再看看文件大小:

$ ln -s a.txt b.txt #軟連接
$ stat -c 'inode %i, links %h' b.txt
inode 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.txt
inode 12058942, links 2

$ ls -l c.txt #大小0字節,和a同樣
lrwxrwxrwx ... 0 ... c.txt

4

但實際生產上,遇到 「刪了log文件、但空間不釋放」 一般和軟/硬連接沒有什麼關係。

我踩的坑多-不會騙你.png

實戰經驗比較豐富的候選人會知道,這每每是由於 log 文件正被另外一個進程打開。

好比在終端 1 打開 a.txt:

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

而後在終端 2 能夠看到該文件被 Python 打開:

$ lsof a.txt
COMMAND  PID ...     NODE NAME
python  2390 ... 12058942 a.txt

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

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

注:0、一、二、3 是內核的 fd 編號。0=stdin, 1=stdout, 2=stder。

能夠看到,a.txt  被標記爲已刪除,但由於進程還開着它,可能會訪問文件的內容,因此內核會等到進程關閉該文件(或進程退出後)纔在磁盤上移除這個文件。

5

在面試中一般沒有機會再問下去了,但實踐中每每問題還沒解決。

好比前述共享開發機,就曾遇到了磁盤空間共800G,但用 du 命令查看,全部文件只佔用了 500G的狀況。

那麼:

1. 如何才能知道如今系統中有哪些文件已刪除、可是仍被佔用呢?

$ sudo lsof | grep deleted
COMMAND   PID  …  NAME
main   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 出來的日誌,就能夠放心刪除了。

對於不支持相似邏輯的服務怎麼辦呢?

重啓大法。

若是不怕背 P0 的話,還能夠這麼做死:

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

注:看起來文件是清空了,但可能存在其餘坑,後果自負。ftruncate只是清空文件,若是想關閉文件,能夠結合 dup、dup二、open和close來搞事,不細說了。

吃藥冷靜一下.png

6

看到這裏你應該明白了爲何前面那個 find 命令不直接用 rm 了吧?

照例總結下:

  1. 能夠用 find 查找文件
  2. 軟連接存的是路徑,硬連接共享inode
  3. 刪除被進程打開的文件,磁盤空間不會釋放
  4. lsof 很好用(不僅是看文件的佔用)

還想知道其餘有意思的面試題嗎?

不如投個簡從來親身體驗下:

~ 投遞連接 ~

投放研發工程師(上海)

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

高級廣告研發工程師(北京)

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

歡迎關注

weixin1.png

相關文章
相關標籤/搜索