
在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
```
**五、预防措施**
- **监控与告警**
-
使用Prometheus+Grafana监控`file-nr`指标。
-
设置告警规则(如FD使用率超过80%时触发)。
- **定期维护**
-
日志轮转(避免日志文件过多占用FD)。
-
定期重启长期运行的服务(如数据库、Web服务器)。
- **压力测试**
- 使用工具(如`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参数)
```
通过以上步骤,可彻底解决文件描述符耗尽问题。关键点在于:
-
**合理设置系统/用户级限制**
-
**定位并修复资源泄漏**
-
**建立长期监控机制**。