不要使用 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?