1. 程式人生 > >[Linux] lsof的錯誤使用場景和檢視開啟檔案數的正確方法

[Linux] lsof的錯誤使用場景和檢視開啟檔案數的正確方法

前兩天在調查一個"too many open files"的問題,和之前一樣,自然而然的用到了lsof,加上一堆漂亮的命令組合來檢視哪些程式打開了很多檔案。
lsof | awk '{print $2}' | uniq -c | sort -rnk1 | head
啪的一敲回車,很順利的定位到幾個docker內執行的Java程序排在最前,分別都是幾萬的結果,懷疑是不是docker的問題。很不幸的是,這個調查結果是錯的。。。

先說真實的情況,後面再展開分析:

  • 真實的元凶,是一個並沒有在上面的命令結果中排在最前面的程序,由於程式設計的bug,不斷的開啟同樣的檔案沒有關閉,真正的佔用了很多fd。
  • CentOS 7中的lsof是按PID/TID/file的組合顯示結果的,上面lsof組合命令顯示“開啟”了很檔案的程序,只是因為程序運行了N個執行緒,而每個執行緒都“用到”了M個jar包,並且FD一欄分別為mem和具體fd號都分別顯示了一次,就出現了2*N*M——上萬條結果。

結論一:
使用lsof檢視fd數是不正確的。
儘管網上很多文章教人這麼用,但實際上不應該這麼做。

這是因為:

  1. lsof的結果包含了並非以fd形式開啟的檔案,比如用mmap方式訪問檔案(FD一欄顯示為mem),實際並不佔用fd。
    其中包括了像.so這樣的檔案。從結果看.jar檔案也是以FD為mem和具體fd編號分別打開了一次。
  2. CentOS 7的lsof(我這裡lsof -v的版本號是4.87)是按PID/TID/file的組合對應一行,不是一行一個fd。同一個程序如果多個執行緒訪問同一個檔案通常只需要開啟一次、佔用一個fd,但在lsof中就顯示多行。
    如果用lsof -p <pid>,則不按TID顯示,結果數少很多。但仍包含了沒有使用fd的檔案。

結論二:
準確的檢視fd使用總數的命令是:
cat /proc/sys/fs/file-nr
或者(結果多的時候執行需要一段時間)
sudo find /proc -print | grep -P '/proc/\d+/fd/'| wc -l

注意如果用
sudo ls -l /proc/*/fd/* | wc -l


結果是不對的,比上面的命令返回結果少很多。原因是實際執行是會把*擴充成具體的目錄作為引數,而這個引數長度有限制。

檢視具體一個程序號的fd數量是:
ls -l /proc/<pid>/fd | wc -l

檢視哪個程序使用的fd最多(再來一路組合拳):
sudo find /proc -print | grep -P '/proc/\d+/fd/'| awk -F '/' '{print $3}' | uniq -c | sort -rn | head

但還要注意上面的命令返回的是系統的fd使用情況,而ulimit的配置是針對單使用者的,兩者是有區別的。

結論三:
不同版本的lsof輸出結果不同。

CentOS 7.3的lsof (我這裡是4.87),按PID/TID/file顯示。CentOS 6.6的lsof(我這裡是4.82),按PID/file顯示。結果數相差很大。但lsof -p <pid>的結果是一致的。
這在容器OS版本和宿主機OS版本不同時就需要注意了,在容器裡和宿主機上用lsof檢視同一程序的結果會很不同,我碰到的就是這種情況。

</br>


之前使用lsof(或lsof -n不解析協議主機名)的相關命令和真實意義:
開啟檔案總記錄數(沒太大意義):
lsof | wc -l

lsof -n | wc -l #不解析協議主機名

檢視哪些pid使用檔案數量最多(其實也沒有太大意義):
lsof | awk '{print $2}' | uniq -c | sort -rnk1 | head



作者:petergz
連結:https://www.jianshu.com/p/407c2baef92e
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。