1. 程式人生 > 其它 >不要使用 lsof 檢查開啟的檔案描述符 file descriptor 數量

不要使用 lsof 檢查開啟的檔案描述符 file descriptor 數量

前言

生產環境的 K8s 節點又被 NodeHasFDPressure 坑了,修改完 limits.conf 直接終端都進不去了……為了快速使服務恢復可用狀態,沒有對節點內部進行更細的排查,直接將節點進行排水處理才使服務正常……

令我略無語的,是在事後的覆盤以及對 FD 問題解決詳細的索引中,發現 lsof 的坑,也是(可能)一直沒能確定 FD 根本問題的所在。

lsof

lsof 的功能是列出開啟的檔案,在 man 手冊的 lsof 描述中,它有一段解釋:

An open file may be a regular file, a directory, a block special file, a character special file, an executing text reference, a library, a stream or a network file (Internet socket, NFS file or UNIX domain socket.)

它解釋道:“一個開啟的檔案可以是一個普通檔案、一個目錄、一個塊狀檔案、一個字元檔案、一個執行中的文字引用、一個庫、一個流或一個網路檔案(網路套接字、NFS 檔案或 UNIX 域套接字”

問題在於, lsof 列出所有開啟的檔案,包括不使用檔案描述符的檔案,所以使用 lsof |wc -l 統計出來的數目,會大於 FD 的 file-max,從而沒法確定真正大量使用 FD 的程序。

這個坑,是跟著自己的片面理解和搜尋引擎上的「引導」,兩腳踩了進去……

實踐

使用 lsof 統計(這裡還 hung 住好一會):

$ lsof| wc -l
2520903

檢視系統的檔案描述符總的限制數:

$ cat /proc/sys/fs/file-max
1048576

這裡便能看出一些問題, lsof 統計的數目明顯大於 file-max ,綜上,lsof 並不適合用來統計開啟的檔案描述符的數量。

那應該如何統計 fd 開啟檔案的數量呢?k8s 的守護程序 NPD 的 fd 檢查指令碼是一個很好的例子,它的內容如下:

$ cat check_fd.sh
#!/bin/bash
# check max fd open files
OK=0
NONOK=1
UNKNOWN=2

cd /host/proc

count=$(find -maxdepth 1 -type d -name '[0-9]*' | xargs -I {} ls {}/fd | wc -l)
max=$(cat /host/proc/sys/fs/file-max)

if [[ $count -gt $((max*80/100)) ]]; then
echo "current fd usage is $count and max is $max"
exit $NONOK
fi
echo "node has no fd pressure"
exit $OK

因為 NPD 把宿主機的 /proc 掛載到了 /host/proc/, 實際上它是遍歷了宿主機 /proc 來統計 FD 數量,然後對 file-max 進行對比來斷言 NodeHasFDPressure

在節點上的操作就可以直接在 /proc 目錄下使用此命令統計 FD 數量了:

$ find -maxdepth 1 -type d -name '[0-9]*' | xargs -I {} ls {}/fd | wc -l
42958

統計前10個最多 fd 開啟數的程序:

$ find -maxdepth 1 -type d -name '[0-9]*' \
     -exec bash -c "ls {}/fd/ | wc -l | tr '\n' ' '" \; \
     -printf "fds (PID = %P), command: " \
     -exec bash -c "tr '\0' ' ' < {}/cmdline" \; \
     -exec echo \; | sort -rn | head

參考連結:
How Many Open Files?
Counting open files per process
fs.txt full documentation
Why file-nr and lsof count on open files differs?