emqx、MongoDB或者java程序,出现 Too many open files 问题
"Too many open files"(太多打开的文件)是一个常见的系统错误,表示一个进程已经达到了它所能打开的最大文件描述符(file descriptor)数量限制。这个错误在类 Unix 系统(如 Linux 和 macOS)中尤为常见。
错误表现形式
当你遇到这个问题时,可能会看到如下错误信息:
- Java 应用:
java.io.IOException: Too many open files - Node.js 应用:
EMFILE: too many open files - Python、Nginx、MySQL 等也都会抛出类似的错误。
 - 系统层面可能显示:
open() failed (24: Too many open files) - EMQX和MongoDB:t
oo many open files 
原因分析
1. 文件描述符耗尽
每个打开的文件、网络连接、管道等在操作系统中都对应一个“文件描述符”(File Descriptor,简称 fd)。操作系统和进程本身对可以打开的文件描述符数量有限制。
2. 资源泄漏(常见原因)
- 程序打开了文件、Socket 或数据库连接但没有正确关闭。
 - 多线程程序中未正确释放资源。
 - 使用异步 IO 或事件驱动模型时忘记清理句柄。
 
3. 系统或用户设置过低
- 默认的 
ulimit设置可能太小,无法支撑高并发应用。 
排查与解决
1. 查看当前限制
使用以下命令查看当前 shell 的文件描述符限制:
ulimit -n 

输出是 1024,是默认值。
2. 查看某个进程的已打开文件数
假设你要查 PID 是 1234 的进程:
lsof -p 1234 | wc -l 
或者
ls /proc/1234/fd | wc -l 
这将告诉你该进程当前打开了多少个文件描述符。
3. 修改系统限制(临时)
ulimit -n 65536 
注意:这只是当前会话有效,重启后失效。
4. 永久修改 ulimit
编辑 /etc/security/limits.conf 文件,添加:
*               soft    nofile          65536
*               hard    nofile          65536 
如果是特定用户(比如 tomcat):
tomcat          soft    nofile          65536
tomcat          hard    nofile          65536 
还要确保 PAM 配置启用 limits:
检查 /etc/pam.d/common-session 是否有:
session required pam_limits.so 
5. 修改 systemd 服务的限制(适用于使用 systemd 的系统)
如果你的服务是通过 systemd 启动的(如 Nginx、Java 应用),需要在服务单元文件中添加:
[Service]
LimitNOFILE=65536 

然后重载 systemd:
systemctl daemon-reexec
systemctl restart your-service 
优化建议
- 定期检查代码中是否及时关闭了文件、Socket、数据库连接等。
 - 对于高并发服务器,建议将最大文件描述符设为 
65536或更高。 - 使用连接池管理数据库连接、HTTP 连接等。
 - 使用工具如 
lsof、strace、netstat来定位资源泄露点。 
示例场景
| 场景 | 可能原因 | 
|---|---|
| Web 服务器(如 Nginx、Tomcat)报错 | 并发太高,fd 不够;或存在连接未关闭 | 
| Java 应用报错 | 打开太多文件或 Socket 没有关闭 | 
| 数据库连接池问题 | 没有释放连接,导致 socket 资源泄漏 | 
小技巧:模拟 Too Many Open Files
你可以用下面的小脚本来测试这个错误:
#!/bin/bash
for i in {1..10000}; doexec 200<$i
done 
运行后就会触发 "Too many open files" 错误。
