在Linux系統中,文件描述符(File Descriptor, FD)是操作系統管理打開文件、套接字、管道等資源的抽象標識。當進程或系統耗盡文件描述符時,會導致服務崩潰、連接失敗等嚴重問題。以下是詳細的排查和解決方案:
---
### **一、問題確認**
#### 1. **檢查當前文件描述符使用情況**
? ?```bash
? ?# 查看系統已使用的FD數量
? ?cat /proc/sys/fs/file-nr
? ?# 輸出示例:7864 ?0 ?9223372036854775807
? ?# 分別表示:已分配FD數 | 未使用FD數 | 系統最大FD限制
? ?# 查看各進程的FD使用量(按使用量排序)
? ?lsof -n | awk '{print $2}' | sort | uniq -c | sort -nr | head
? ?```
#### 2. **確認系統級限制**
? ?```bash
? ?# 查看系統全局限制
? ?cat /proc/sys/fs/file-max
? ?# 臨時修改限制(重啟失效)
? ?sysctl -w fs.file-max=1000000
? ?```
#### 3. **檢查用戶級限制**
? ?```bash
? ?# 查看當前用戶的軟/硬限制
? ?ulimit -n ? ? ?# 軟限制
? ?ulimit -Hn ? ? # 硬限制
? ?```
---
### **二、臨時解決方案**
#### 1. **增加進程的FD限制**
? ?```bash
? ?# 臨時提高當前會話的限制(僅對當前Shell有效)
? ?ulimit -n 65535
? ?```
#### 2. **重啟受影響的服務**
? ?```bash
? ?# 找到高FD占用的進程并重啟
? ?systemctl restart <service_name>
? ?```
---
### **三、永久解決方案**
#### 1. **修改系統全局限制**
? ?```bash
? ?# 編輯/etc/sysctl.conf,增加以下行
? ?fs.file-max = 1000000
? ?# 生效配置
? ?sysctl -p
? ?```
#### 2. **修改用戶級限制**
? ?```bash
? ?# 編輯/etc/security/limits.conf,針對用戶或組設置
? ?* soft nofile 65535 ? ?# 所有用戶軟限制
? ?* hard nofile 100000 ? # 所有用戶硬限制
? ?# 特定用戶示例
? ?www-data soft nofile 50000
? ?www-data hard nofile 100000
? ?```
#### 3. **修改服務單元配置(Systemd)**
? ?```bash
? ?# 編輯服務配置文件(如nginx)
? ?sudo systemctl edit nginx.service
? ?# 添加以下內容:
? ?[Service]
? ?LimitNOFILE=100000
? ?# 重載并重啟服務
? ?systemctl daemon-reload
? ?systemctl restart nginx
? ?```
---
### **四、深入排查與優化**
#### 1. **定位FD泄漏的進程**
? ?```bash
? ?# 統計進程FD使用量
? ?ps aux | awk '{print $2}' | xargs -I {} sh -c 'echo {} $(ls /proc/{}/fd/ 2>/dev/null | wc -l)' | sort -k2 -nr | head
? ?```
#### 2. **分析FD類型**
? ?```bash
? ?# 查看某進程打開的FD詳情(替換<PID>)
? ?ls -l /proc/<PID>/fd
? ?# 檢查是否有異常(如大量未關閉的socket或文件)
? ?```
#### 3. **代碼層面修復**
? ?- **檢查應用程序**:確保文件、套接字、數據庫連接等資源使用后正確關閉。
? ?- **使用工具檢測**:
? ? ?- `valgrind`(C/C++內存和FD泄漏檢測)
? ? ?- `lsof -p <PID>`(實時監控進程FD)
#### 4. **內核參數調優(高并發場景)**
? ?```bash
? ?# 增加TCP連接相關限制(避免socket耗盡)
? ?echo "net.ipv4.tcp_max_tw_buckets = 200000" >> /etc/sysctl.conf
? ?echo "net.core.somaxconn = 65535" >> /etc/sysctl.conf
? ?sysctl -p
? ?```
---
### **五、預防措施**
1. **監控與告警**
? ?- 使用Prometheus+Grafana監控`file-nr`指標。
? ?- 設置告警規則(如FD使用率超過80%時觸發)。
2. **定期維護**
? ?- 日志輪轉(避免日志文件過多占用FD)。
? ?- 定期重啟長期運行的服務(如數據庫、Web服務器)。
3. **壓力測試**
? ?- 使用工具(如`ab`、`wrk`)模擬高并發場景,提前發現FD瓶頸。
---
### **六、常見場景示例**
#### **案例1:Nginx服務器FD耗盡**
? ?```bash
? ?# 1. 修改Nginx配置
? ?worker_rlimit_nofile 100000;
? ?events {
? ? ? ?worker_connections 50000;
? ?}
? ?# 2. 調整Systemd限制(見上文)
? ?```
#### **案例2:MySQL連接泄漏**
? ?```sql
? ?-- 查看當前連接數
? ?SHOW STATUS LIKE 'Threads_connected';
? ?-- 優化連接池配置(如JDBC的maxActive參數)
? ?```
---
通過以上步驟,可徹底解決文件描述符耗盡問題。關鍵點在于: ?
1. **合理設置系統/用戶級限制** ?
2. **定位并修復資源泄漏** ?
3. **建立長期監控機制**。