當伺服器達到檔案描述符限制時,你的系統往往會立刻出現問題。你可能會注意到 CPU 使用率升高、連線失敗,或者出現一些難以直接定位原因的異常現象。這些症狀會打亂你的工作流程,也會影響使用者體驗。及時處理有助於你恢復伺服器的正常運作,並防止資料遺失。

  • CPU 使用率高
  • 連線失敗
  • 難以追蹤的問題症狀

只要採取正確的步驟,你就可以解決這些問題,並讓伺服器持續平穩運作。

檔案描述符限制問題的緊急處理步驟

常見症狀與錯誤訊息

當伺服器觸及檔案描述符限制時,你可能會發現系統行為異常。應用程式可能停止回應,使用者可能會遇到連線失敗。有時,你還會在日誌中看到一些指向資源問題的錯誤訊息。以下是最常見的一些錯誤:

錯誤訊息說明
ERROR: lib_htresponse: htresponseGetContentBlock: Failed to allocate the content block處理內容時發生記憶體配置失敗。
ERROR: lib_htresponse: htresponseGetChunk: Failed to allocate the chunk分塊處理時發生記憶體配置失敗。
ERROR: lib_htrequest: htrequestWrite: Failed to allocate memory一般記憶體配置失敗。
ERROR: as_handler: failed to create pool建立資源池時因超出資源限制而失敗。
[alert] (11)Resource temporarily unavailable: apr_thread_create: unable to create worker thread由於資源限制,無法建立工作執行緒。
[alert] (12)Cannot allocate memory: apr_thread_create: unable to create worker thread建立工作執行緒時發生記憶體配置失敗。
[error] server reached MaxClients setting, consider raising the MaxClients setting表示伺服器已達到最大用戶端連線數限制。

你應當檢查日誌中是否出現這些訊息。它們能夠幫助你確認:已開啟的檔案描述符數量已經達到了系統範圍內的限制。

快速釋放檔案描述符

面對這種問題時,你需要盡快採取行動。首先,找出哪些行程占用了最多的已開啟檔案描述符。你可以使用下面的命令列出所有已開啟的檔案:

lsof | less

如果你想查看哪個行程占用最多,可以嘗試:

lsof | awk '{print $2}' | sort | uniq -c | sort -nr | head

這條命令會顯示檔案描述符計數最高的行程 ID。如果你發現某個行程本不應占用如此多的檔案,可以停止它或重新啟動它。你也可以關閉未使用的應用程式或連線。這樣可以釋放資源,幫助伺服器恢復正常。

提示:有時,單一應用程式可能會發生檔案描述符洩漏。請檢查是否存在失控成長的日誌檔,或卡住的網路連線。

重新啟動服務或行程

如果釋放資源後問題仍未解決,你可能需要重新啟動相關服務。重新啟動服務會釋放它目前持有的全部檔案描述符。可以使用以下命令重新啟動服務(將 service_name 替換為實際服務名稱):

sudo systemctl restart service_name

如果你不知道是哪一個服務引發了問題,可以先重新啟動最常見的關鍵服務,例如 Web 伺服器或資料庫伺服器。在某些情況下,你可能還需要重新啟動整台伺服器。不過,這應當作為最後手段。

你也可以透過以下命令查看目前 shell 工作階段允許開啟的最大檔案描述符數量:

ulimit -n

如果你需要暫時提高限制,可以使用:

ulimit -n 4096

這條命令會為目前工作階段設定新的限制。請記住,這項變更不會影響其他使用者,也不會改變系統範圍的限制。

依照這些步驟操作後,你可以快速恢復正常運作。同時,在進一步排查根本原因的過程中,也能避免問題持續擴大。

檢查已開啟的檔案描述符數量

使用 lsof 和其他工具

你需要知道伺服器目前使用了多少已開啟的檔案描述符。lsof 命令可以清楚展示所有已開啟的檔案,並幫助你迅速定位問題。你可以使用以下命令進行檢查與監控:

  • lsof:列出所有已開啟的檔案,包括 socket 和 pipe。
  • sudo lsof | head -20:顯示前 20 個已開啟的檔案。使用 sudo 可取得完整結果。
  • sudo lsof | awk 'NR>1 {print $1, $2}' | sort | uniq -c | sort -rn | head -20:統計每個行程的已開啟檔案描述符數量並依降冪排序。
  • lsof -p $(pgrep myapp) | wc -l:統計指定行程的檔案描述符數量。
  • watch -n 2 "lsof -p $(pgrep myapp) | wc -l":每兩秒監控一次某個行程的檔案描述符數量。

lsof 工具能幫助你找出哪些行程消耗了最多資源。你也可以藉此發現被鎖定或未釋放的檔案,這些都可能是問題根源。如果你發現某個行程的計數異常偏高,那麼你很可能已經找到了問題所在。

使用 ulimit 和系統檔案查看限制

你還應當檢查目前工作階段的檔案描述符限制。ulimit -n 命令會顯示允許開啟的最大檔案描述符數量。如果你想調整目前工作階段的限制,可以使用 ulimit -n <number>。如果需要更細緻的控制,可以使用 ulimit -Sn <number> 設定軟限制,或使用 ulimit -Hn <number> 設定硬限制。

如果你希望永久生效,就需要編輯系統檔案。請更新 /etc/security/limits.conf 來設定使用者層級限制,或更新 /etc/systemd/system.conf 來設定服務層級限制。在修改系統服務限制後,請執行 systemctl daemon-reload,然後重新啟動對應服務。

下表展示了常見 Linux 系統上的預設限制:

發行版 / 系統軟限制硬限制
Home Assistant OS1024524288
Linux 系統1024N/A
systemd 240 或更新版本1024524288

如果你執行的是大型應用或多個服務,就應當檢查並修改系統限制。這一步能幫助你避免再次觸及檔案描述符上限。

提高檔案描述符限制

當你達到檔案描述符限制時,需要迅速處理,以維持伺服器穩定。提高限制主要有兩種方式:一種是暫時提高目前工作階段的限制,另一種是永久提高整個系統的限制。你應根據自身需求以及所執行應用的類型選擇合適的方法。

使用 ulimit 進行暫時修改

你可以使用 ulimit 命令修改目前 shell 工作階段允許開啟的最大檔案描述符數量。這種方式適合快速應急,也適合在永久修改前先做測試。高負載環境,例如繁忙的 Web 伺服器或資料庫伺服器,在流量高峰時通常需要更高的限制。備份工具、檔案同步程式以及存在檔案描述符洩漏的應用,也都可能從暫時提高限制中受益。

常見需要提高限制的情境包括:

  • 擁有大量工作執行緒或 goroutine 的應用程式
  • 一次性開啟大量 socket 或檔案的程式
  • 處理高流量或大量連線的伺服器
  • 未正確輪替或關閉的日誌檔案

要查看目前限制,請執行:

ulimit -n

要為目前工作階段設定新的限制,請使用:

ulimit -n 65536

該命令會將目前 shell 的已開啟檔案描述符數量限制設定為 65,536。如果你關閉 shell 或重新啟動伺服器,限制會恢復為預設值。若要設定非常高的數值,可能需要超級使用者權限。

如果設定得過低,你可能會看到諸如 Nginx 拒絕新連線、MongoDB 無法讀寫資料之類的錯誤。其他應用程式也可能因無法開啟足夠多的檔案而停止運作。

在 sysctl.conf 和 limits.conf 中進行永久修改

若要獲得長期解決方案,你應當更新系統設定檔。sysctl.conf 檔案控制系統範圍內的檔案控制代碼限制。參數 fs.file-max 用於設定核心可使用的最大檔案控制代碼數量。對於執行大量應用程式或同時處理大量使用者的伺服器來說,這個設定尤其重要。

如果你不提高系統範圍的限制,可能會看到「Too many open files」之類的錯誤。這些錯誤可能引發程式崩潰與服務中斷。你還應更新 /etc/security/limits.conf 來設定使用者層級限制。這個檔案允許你控制每個使用者或群組能夠開啟多少檔案。

要修改系統範圍限制,請在 /etc/sysctl.conf 中加入以下內容:

fs.file-max = 100000

使用以下命令套用變更:

sudo sysctl -p

要設定使用者限制,請在 /etc/security/limits.conf 中加入如下內容:

* soft nofile 65536
* hard nofile 65536

星號(*)表示該規則適用於所有使用者。如果你願意,也可以將其替換為某個具體使用者名稱。軟限制是 shell 預設使用的值,硬限制則是你可設定的最大值。修改後,你可能需要登出並重新登入,才能讓這些變更生效。

為 systemd 服務套用變更

許多現代 Linux 系統使用 systemd 來管理服務。要更改這些服務的檔案描述符限制,你必須更新服務設定。請依照以下步驟操作:

  1. 為你的服務建立一個覆寫設定檔:
    sudo systemctl edit your-service-name.service
  2. [Service] 區段下加入這一行:
    LimitNOFILE=65536
  3. 重新載入 systemd 常駐程式:
    sudo systemctl daemon-reload
  4. 重新啟動你的服務:
    sudo systemctl restart your-service-name.service
  5. 檢查新的限制是否已經生效。先找到主行程 ID:
    systemctl status your-service-name.service

    然後執行:

    cat /proc/[PID]/limits | grep "Max open files"

你也可以使用 systemd-delta --type=extended 來確認變更是否已生效。命令 systemctl status your-service-name.service 也會顯示目前設定。

提示:每次修改後都要重新載入 systemd 常駐程式。並且要重新啟動服務,新的設定才會真正套用。

透過這些步驟,你可以控制應用程式能夠使用的檔案描述符數量。這有助於避免服務故障,並維持伺服器平穩運作。

防止檔案描述符耗盡

使用 Netdata 或 Zabbix 進行監控

你可以透過使用具備即時資料和警示能力的監控工具,來防止檔案描述符耗盡。Netdata 和 Zabbix 都可以幫助你追蹤已開啟的檔案和 socket,而無需手動反覆檢查。這些工具能讓你在問題影響使用者之前就及時發現異常。

工具優勢
Netdata零設定即可獲得即時洞察,並支援按秒級蒐集資料。
Zabbix監控能力全面,具備強大的歷史資料儲存與可自訂警示功能。

Netdata 提供即時可視性,因此你可以在變化發生時立即看到。Zabbix 則支援監控大量裝置與應用,並能保存資料用於長期分析。兩者都能減少你在手動監控上花費的時間與精力。你還可以設定警示,在使用量接近檔案描述符限制時提前收到通知。

提示:自動化監控能讓你在專注其他工作的同時,依然有信心及早發現問題。

最佳化日誌與應用程式設定

你應當檢查應用程式設定,避免不必要的檔案描述符占用。很多應用會因為日誌記錄、網路連線或快取機制而開啟檔案或 socket。如果不對這些設定進行最佳化,就可能遇到「Too many open files」之類的錯誤。

參數說明
檔案描述符每個 socket 連線都會占用一個檔案描述符。合理調校這一數值可提升可用性。
Accept Backlog控制有多少個 TCP 連線可以在佇列中等待處理。設定該值有助於管理負載。
Socket Health Check透過調整健康檢查逾時,只保留健康連線,減少資源浪費。

你應當在讀取或寫入設定檔後立即關閉檔案描述符。盡量將已開啟的檔案描述符數量保持在 50 以下。定期重新啟動應用程式,有助於清理未使用的資源。還要始終檢查 ulimit 設定,確保應用程式能夠承受預期負載。

定期檢視與團隊意識建立

你可以把定期稽核納入日常流程,以防止未來再次出現問題。經常檢查伺服器資源使用情況和設定檔。對伺服器進行壓力測試,了解其極限並為未來成長做好規劃。使用限流機制來控制伺服器接受的請求數量。

  • 訓練團隊掌握資源管理模式。
  • 分享與資源洩漏相關事故的事後檢討與復盤總結。
  • 將資源管理納入編碼規範。
  • 為高風險程式碼區域制定檢查清單。

定期檢視和團隊訓練能幫助每個人在問題變得嚴重之前,就及時發現並修復它們。

你可以透過以下步驟解決檔案描述符限制問題:

  1. 以預期尖峰負載的兩倍對伺服器進行測試。
  2. 監控檔案描述符數量和 TCP 狀態。
  3. 在伺服器初始部署時就設定好 ulimits

對於高併發伺服器,請持續關注各項指標,並謹慎調整限制。如果設定過高,可能會帶來系統不穩定的風險。

最佳實務命令範例
提高檔案描述符數量echo "* soft nofile 1000000" >> /etc/security/limits.conf
提高系統範圍限制echo "fs.file-max = 2000000" >> /etc/sysctl.conf

保持主動預防,並持續學習,才能更好地守護伺服器的健康運作。

常見問題

什麼是檔案描述符?

檔案描述符是作業系統用來追蹤已開啟檔案、socket 或 pipe 的一個數字識別。每個執行中的行程都有自己的一組檔案描述符。

我要怎麼知道伺服器是否達到了檔案描述符限制?

你可能會在日誌中看到「Too many open files」這樣的錯誤。使用 lsofulimit -n 可以檢查目前使用情況與限制值。

我可以在不重新啟動伺服器的情況下提高檔案描述符限制嗎?

你可以使用 ulimit -n <number> 提高目前工作階段的限制。若要永久生效,則必須更新系統檔案,並重新啟動受影響的服務。

是什麼導致檔案描述符洩漏?

應用程式可能沒有正確關閉檔案或 socket。不良的日誌處理方式或程式碼中的缺陷,通常都會導致洩漏。定期監控有助於你及早發現這些問題。