這個問題經常在Linux上出現,而且常見於高並發訪問文件系統、多線程網絡連接等場景。之所以出現這個問題,大多數情況是你的程序沒有正常關閉一些資源引起的。
在Linux系統中,目錄、字符設備、塊設備、套接字、打印機等都被抽象成了文件,即通常所說的“一切皆文件”。程序操作這些文件時,系統就需要記錄每個當前訪問file的name、location、access authority等相關信息,這樣一個實體被稱為file entry。這些實體被記錄在open files table中,Linux系統配置了open files table中能容納多少file entry。如果超過這個配置值,則Linux就會拒絕其他文件操作的請求,並拋出Too many open files。
解決這個問題可以從兩方面着手,一是可以修改系統的配置信息;另外一個是從你的程序層面解決。
修改系統配置
根據應用權限,又可以分為系統級和用戶級。系統級的修改會對所有用戶有效,而用戶級只限制每個登錄用戶的可連接文件數。
系統級
通過命令來查看fs.file-max的配置數量
cat /proc/sys/fs/file-max
或者
sysctl -a
- 改動可以分為臨時改動和永久改動,
- 臨時改動直接可用
sysctl -w [變量名]=[值]來解決。例如:
synctl -w fs.file-max=4096
- 永久改動就需要修改/etc/sysctl.conf文件
如果文件中沒有fs.file-max屬性,則添加。設置完成后,使用sysctl -p來加載系統參數,在不指定文件位置的情況下,默認會從/etc/sysctl.conf文件中加載。
用戶級
直接通過命令ulimit -n 設置的數量進行配置,例如:
ulimit -n 2048。
修改代碼
上面那種方法在你的代碼沒有問題的情況下,可能能解決問題。但是如果是你的程序的原因,則很難有效的解決問題。所以出現這個問題,應該首先檢查的你程序,是不是打開的文件或socket沒有正常關閉。
命令可以查看你進程打開的文件,進程打開的端口(TCP、UDP)。由於該命令需要訪問核心內存和各種文件,所以需要root用戶才能執行。lsof -c 進程名列出指定進程所打開的文件或者lsof -p 進程號列出指定進程號所打開的文件。
lsof -c PID
例如Go程序中忘記文件流的關閉、解鎖一個加鎖的資源、關閉數據庫鏈接等。都會造成open too many files的問題,尤其是在高並發的情況下。所以比較好的習慣就是在進行以上資源操作時,緊跟着使用defer語句。它可以用來推遲執行某個語句或函數到任意位置執行return語句之后。