如何解決 Linux 上的“打開文件過多”錯誤
已發表: 2022-06-29在 Linux 計算機上,系統資源在用戶之間共享。 嘗試使用超過您的公平份額,您將達到上限。 您還可能成為其他用戶或進程的瓶頸。
共享系統資源
在其他大量工作中,Linux 計算機的內核總是忙於觀察誰在使用多少有限的系統資源,例如 RAM 和 CPU 週期。 多用戶系統需要持續關注以確保人員和進程不會使用超出適當範圍的任何給定係統資源。
例如,對於某人佔用如此多的 CPU 時間以致其他人感覺計算機運行緩慢是不公平的。 即使您是唯一使用 Linux 計算機的人,也為您的進程可以使用的資源設置了限制。 畢竟,您仍然只是另一個用戶。
一些系統資源是眾所周知且顯而易見的,例如 RAM、CPU 週期和硬盤空間。 但是還有很多很多的資源需要監控,每個用戶——或者每個用戶擁有的進程——都有一個設定的上限。 其中之一是進程一次可以打開的文件數。
如果您曾經在終端窗口中看到“打開的文件過多”錯誤消息或在系統日誌中發現它,則表示已達到上限,並且不允許該進程打開更多文件。
這不僅僅是您打開的文件
Linux 可以處理的打開文件的數量存在系統範圍的限制。 正如我們將看到的,這是一個非常大的數字,但仍有一個限制。 每個用戶進程都有一個他們可以使用的分配。 他們每個人都獲得分配給他們的系統總數的一小部分。
實際分配的是一些文件句柄。 每個打開的文件都需要一個句柄。 即使分配相當大,系統範圍內的文件句柄也會比您最初想像的更快用完。
Linux 對幾乎所有內容進行了抽象,使其看起來好像是一個文件。 有時它們只是簡單的舊文件。 但其他操作(例如打開目錄)也使用文件句柄。 Linux 使用塊特殊文件作為硬件設備的一種驅動程序。 字符特殊文件非常相似,但它們更常用於具有吞吐量概念的設備,例如管道和串行端口。
塊特殊文件一次處理數據塊,字符特殊文件分別處理每個字符。 這兩個特殊文件都只能通過使用文件句柄來訪問。 程序使用的庫使用文件句柄,流使用文件句柄,網絡連接使用文件句柄。
抽像出所有這些不同的需求,使它們以文件的形式出現,從而簡化了與它們的交互,並允許管道和流等工作。
您可以看到,Linux 在幕後打開文件並使用文件句柄只是為了運行自己——別管您的用戶進程。 打開文件的數量不僅僅是您打開的文件數量。 操作系統中的幾乎所有東西都在使用文件句柄。
文件句柄限制
使用此命令可以查看系統範圍的最大文件句柄數。
cat /proc/sys/fs/file-max
這返回了一個荒謬的大量 9.2 quintillion。 這是理論系統的最大值。 這是您可以在 64 位有符號整數中保存的最大可能值。 你那台糟糕的電腦是否真的能處理一次打開的這麼多文件完全是另一回事。
在用戶級別,您可以擁有的打開文件的最大數量沒有明確的值。 但是我們可以大致算出來。 要找出您的一個進程可以打開的最大文件數,我們可以使用帶有-n
(打開文件)選項的ulimit
命令。
ulimit -n
為了找到用戶可以擁有的最大進程數,我們將使用ulimit
和-u
(用戶進程)選項。
ulimit -u
將 1024 和 7640 相乘得到 7,823,360。 當然,其中許多進程已經被您的桌面環境和其他後台進程使用。 所以這是另一個理論上的最大值,而且你永遠無法實現。
重要的數字是進程可以打開的文件數。 默認情況下,這是 1024。值得注意的是,同時打開同一個文件 1024 次與同時打開 1024 個不同文件相同。 一旦你用完所有的文件句柄,你就完成了。
可以調整進程可以打開的文件數量。 在調整此數字時,實際上需要考慮兩個值。 一個是當前設置的值,或者您嘗試設置的值。 這稱為軟限制。 還有一個硬限制,這是您可以將軟限制提高到的最高值。
考慮這一點的方式是軟限制實際上是“當前值”,而上限是當前值可以達到的最高值。 普通的非 root 用戶可以將他們的軟限制提高到任何值,直到他們的硬限制。 root 用戶可以增加他們的硬限制。
要查看當前的軟限制和硬限制,請將ulimit
與-S
(軟)和-H
(硬)選項以及-n
(打開文件)選項一起使用。
ulimit -Sn
ulimit -Hn
為了創造一種我們可以看到正在實施的軟限制的情況,我們創建了一個重複打開文件直到失敗的程序。 然後它在放棄它使用的所有文件句柄之前等待擊鍵。 該程序稱為open-files
。
./open-文件
它打開 1021 個文件並在嘗試打開文件 1022 時失敗。
1024 減去 1021 是 3。其他三個文件句柄發生了什麼? 它們用於STDIN
、 STDOUT
和STDERR
流。 它們是為每個進程自動創建的。 它們的文件描述符值始終為 0、1 和 2。
相關:如何使用 Linux lsof 命令
我們可以使用帶有-p
(進程)選項的lsof
命令和open-files
程序的進程 ID 來查看這些內容。 方便地,它將其進程 ID 打印到終端窗口。
lsof -p 11038
當然,在實際情況下,您可能不知道哪個進程剛剛吞噬了所有文件句柄。 要開始您的調查,您可以使用此管道命令序列。 它會告訴您計算機上文件句柄最多產的 15 個用戶。
lsof | awk '{ 打印 $1 " " $2; }' | 排序-rn | 唯一的-c | 排序-rn | 頭 -15
要查看更多或更少的條目,請將-15
參數調整到head
命令。 一旦你確定了這個進程,你需要弄清楚它是否已經失控並打開了太多的文件,因為它失去了控制,或者它是否真的需要這些文件。 如果確實需要它們,則需要增加其文件句柄限制。
增加軟限制
如果我們增加軟限制並再次運行我們的程序,我們應該會看到它打開了更多文件。 我們將使用ulimit
命令和-n
(打開文件)選項,數值為 2048。這將是新的軟限制。
ulimit -n 2048
這次我們成功打開了2045個文件。 正如預期的那樣,這比 2048 少 3,因為文件句柄用於STDIN
、 STDOUT
和STDERR
。
進行永久性更改
增加軟限制只會影響當前的 shell。 打開一個新的終端窗口並檢查軟限制。 您會看到它是舊的默認值。 但是有一種方法可以為進程可以擁有的打開文件的最大數量全局設置一個新的默認值,該值是持久的並且在重新啟動後仍然存在。
過時的建議通常建議您編輯“/etc/sysctl.conf”和“/etc/security/limits.conf”等文件。 但是,在基於 systemd 的發行版上,這些編輯並不能始終如一地工作,尤其是對於圖形登錄會話。
此處顯示的技術是在基於 systemd 的發行版上執行此操作的方法。 我們需要處理兩個文件。 第一個是“/etc/systemd/system.conf”文件。 我們需要使用sudo
。
須藤 gedit /etc/systemd/system.conf
搜索包含字符串“DefaultLimitNOFILE”的行。 從行的開頭刪除哈希“#”,並將第一個數字編輯為您想要的新進程軟限制。 我們選擇了 4096。該行的第二個數字是硬限制。 我們沒有對此進行調整。
保存文件並關閉編輯器。
我們需要對“/etc/systemd/user.conf”文件重複該操作。
須藤 gedit /etc/systemd/user.conf
對包含字符串“DefaultLimitNOFILE”的行進行相同的調整。
保存文件並關閉編輯器。 您必須重新啟動計算機或使用帶有daemon-reexec
選項的systemctl
命令,以便重新執行systemd
並獲取新設置。
sudo systemctl daemon-reexec
打開終端窗口並檢查新限制應該會顯示您設置的新值。 在我們的例子中是 4096。
ulimit -n
我們可以通過重新運行我們的文件貪婪程序來測試這是一個實時的、可操作的值。
./open-文件
該程序無法打開文件編號 4094,這意味著 4093 是打開的文件。 這是我們的預期值,比 4096 小 3。
一切都是文件
這就是Linux如此依賴文件句柄的原因。 現在,如果您開始用完它們,您就知道如何增加配額。
相關: Linux 上的標準輸入、標準輸出和標準錯誤是什麼?