too many open files linux服務器 golang java
1. 現象
服務的cpu跑滿(golang實現), 並大量報too many open files錯誤.服務使用systemd來運行,部署在阿裏ecs上.
2.分析
從日誌來看,cpu的上升主要為到達文件數限制引起的,但之前已經更改過系統的文件數及所有用戶的文件數,按道理是不應該出現這個問題的,後來查閱資料發現,文件數可以從三個維度限制分別為操作系統限制,用戶態限制,以及進程限制,對於這三個維度選取最小值生效.於是對系統進行分析.
首先查看當前打開文件數, 進程占用的文件數並不多.
lsof -n|awk ‘{print $2}‘|sort|uniq -c|sort -nr|more
然後獲取系統級文件數限制
輸入命令
cat /etc/sysctl.conf
得到
fs.file-max = 1000000
查詢用戶級文件數限制
cat /etc/security/limits.conf
得到
* soft nofile 655350
* hard nofile 655350
單獨獲取程序文件數限制(9928為進程id)
cat /proc/9928/limits
得到
Max open files 1024 4096 files
如上可以發現, 雖然系統及用戶的文件數調大了,但是程序的仍然是一個很低的值, 這裏進程的文件數一般情況下是默認繼承用戶級的值的,而這裏卻沒有繼承
百思不得其解的情況下在systemd的啟動腳本裏加了文件數的初始化值.
如下:
[Service]
Type=simple
LimitNOFILE=40960
LimitNPROC=40960
單獨獲取程序(9928為進程id)
cat /proc/9928/limits
得到
Max open files 40960 40960 files
發現文件數被設置成了啟動時的初始化值.至於為什麽沒有繼承用戶級的值,懷疑是程序裏做了參數設置
3. 總結
歸結來說出現文件描述符的錯誤的排查步驟如下:
首先,判斷配置參數是否正確,這裏涉及到對上面提到的三個維度的檢查,特別時進程維度的,如果只是ulimit -n 一下就完事了,那估計舊要像我一樣進坑了.
如果參數都正確,那麽查看一下當前系統被使用了多少文件數,如果使用的確實多,那要看一下使用在什麽地方,這裏一般有兩種情況,大量連接未關閉,或者大量讀文件的句柄未關閉.具體原因相信到這裏就可以排查出來了.
too many open files linux服務器 golang java