1. 程式人生 > >golang 程序出現too many open files的排查過程

golang 程序出現too many open files的排查過程

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啟動的問題,但是手寫了另外一個測試服務,發現該服務又繼承了使用者檔案數.

百思不得其解的情況下在systemd的啟動腳本里加了檔案數的初始化值.

 如下:

[Service]

Type=simple

LimitNOFILE=40960

LimitNPROC=40960

單獨獲取程式(9928為程序id)

cat /proc/9928/limits

得到

Max open files 40960 40960 files


發現檔案數被設定成了啟動時的初始化值.至於為什麼沒有繼承使用者級的值,懷疑是程式裡做了引數設定,這裡如果有人知道golang裡具體情況的話,還望不吝賜教.

3. 總結

歸結來說出現檔案描述符的錯誤的排查步驟如下:

首先,判斷配置引數是否正確,這裡涉及到對上面提到的三個維度的檢查,特別時程序維度的,如果只是ulimit -n 一下就完事了,那估計舊要像我一樣進坑了.

如果引數都正確,那麼檢視一下當前系統被使用了多少檔案數,如果使用的確實多,那要看一下使用在什麼地方,這裡一般有兩種情況,大量連線未關閉,或者大量讀檔案的控制代碼未關閉.具體原因相信到這裡就可以排查出來了.