線上環境遇到一個隱蔽問題:伺服器重啟後,執行 nginx -s reload 配置不生效,錯誤日誌顯示 Too many open files。經排查發現,Nginx Master 進程的文件描述符限制未生效,導致重新打開大量日誌文件失敗。本文從 Linux 啟動流程、Nginx 進程模型、資源限制生效時機三個維度深度剖析根因。
nginx -tnginx -s reopen,需打開所有 access/error lognginx -s quit第 2 步若因文件描述符不足失敗,整個 reload 就會中斷。
Nginx 兩類進程:
# cat /proc/2398/limits
Max open files 1024 4096 files
# cat /proc/2300/limits
Max open files 409600 409600 files
Master 進程的 Soft Limit 僅 1024,遠低於配置的 409600,導致打開大量日誌文件時觸發 EMFILE。
| 層級 | 配置項 | 線上值 | 狀態 |
|---|---|---|---|
| Nginx 配置 | worker_rlimit_nofile | 409600 | ✓ 正確 |
| 系統級 | /etc/security/limits.conf | * soft/hard nofile 655350 | ✓ 正確 |
| 內核級 | /etc/sysctl.conf fs.file-max | 6553600 | ✓ 正確 |
所有配置均正確,但重啟後 Master 進程未生效。
/etc/inittab 確定運行級別(如 3)/etc/rc.d/rc.sysinit 系統初始化/etc/rc.d/rc 對應級別腳本/etc/rc.d/rc.local(啟動過程最後一個腳本)/bin/login,用戶登入時才讀取 /etc/profile、~/.bash_profile,**此時 limits.conf 才生效**關鍵點:Nginx 通常在 rc.local 階段啟動,早於用戶登入,此時 limits.conf 尚未生效,Master 進程繼承的是系統預設限制(1024)。
編輯 /etc/rc.local,在 Nginx 啟動命令**之前**加入:
ulimit -HSn 655350
/usr/local/nginx/sbin/nginx
-H 設 Hard Limit,-S 設 Soft Limit,-n 指定文件描述符數量。此命令在當前 Shell 生效,後續 fork 的 Nginx Master 進程將繼承此限制。
# 重啟後檢查 Master 進程 PID
cat /proc/$(pgrep -f "nginx: master")/limits | grep "Max open files"
# 預期輸出:Max open files 655350 655350 files
# 減少 TIME_WAIT 佔用,降低內核負載
net.ipv4.tcp_max_tw_buckets = 18000
觀察連接狀態分佈:
ss -an | awk '{print $1}' | sort | uniq -c | sort -rn
server_names_hash_max_size 512000;
server_names_hash_bucket_size 64;
map_hash_max_size 204800;
map_hash_bucket_size 64;
根據業務實際情況調整 server_names_hash、map_hash,避免哈希桶衝突導致性能下降。
核心根因在於 系統啟動順序導致 limits.conf 生效晚於 Nginx 啟動。解決關鍵是在 rc.local 中 Nginx 啟動前顯式執行 ulimit -HSn。建議將此操作納入基礎環境初始化腳本,避免後續擴容遺漏。