Apache出现“Too many open files”错误需三步协同调优:一、通过systemd配置LimitNOFILE=65536或limits.conf设用户级软硬限制;二、按MPM模式适配——prefork下MaxClients≤LimitNOFILE/32,event下可设更高MaxRequestWorkers;三、重启后用cat /proc/PID/limits和lsof验证生效。

Apache 在 Linux 上运行时,每个子进程都需要打开文件(比如日志、配置、静态资源、PHP 文件等),而系统默认对单个进程能打开的文件数有限制(通常是 1024)。如果并发请求多、静态资源多或启用了大量模块,很容易触发 Too many open files 错误,导致请求失败或服务降级。
要让 Apache 子进程能稳定处理更多连接和资源,关键不是只改 Apache 配置,而是系统限制 + Apache 进程行为 + MPM 模式三者协同调整。
查看当前限制并确认瓶颈
先检查实际运行中的限制:
# 查看 Apache 主进程的 limits(用 root 或 apache 用户 pid) cat /proc/$(pgrep -f "httpd|apache2" | head -1)/limits | grep "Max open files"
如果显示 Max open files: 1024 1024 files,说明没调高,就是瓶颈来源之一。
同时确认当前 MPM 类型:
httpd -V | grep MPM # 或 apachectl -V | grep MPM
常见输出如 prefork.c 或 event.c —— 不同 MPM 对文件描述符的需求逻辑不同。
调整系统级文件描述符限制
Apache 子进程继承父进程的 ulimit,所以需在启动环境里设好:
方法一:通过 systemd(推荐,适用于 CentOS 8+/Ubuntu 16.04+)
编辑 Apache 服务单元文件:
sudo systemctl edit httpd # 或 apache2
加入:
[Service] LimitNOFILE=65536 LimitNPROC=65536
保存后重载:
sudo systemctl daemon-reload sudo systemctl restart httpd
方法二:修改 /etc/security/limits.conf(适用于 SysV 或非 systemd 环境)
添加:
www-data soft nofile 65536 www-data hard nofile 65536 apache soft nofile 65536 apache hard nofile 65536
注意:
www-data是 Debian/Ubuntu 默认用户,apache是 RHEL/CentOS 默认用户。需匹配你User和Group配置。
然后确保 PAM 加载 limits(检查 /etc/pam.d/common-session 是否含 session required pam_limits.so)。
Apache 配置中适配 MPM 特性
Prefork 模式(每个请求一个进程)
- 每个子进程独立占用文件描述符;
-
MaxClients× 平均每进程打开文件数 ≈ 总需nofile; - 建议
MaxClients≤LimitNOFILE / 20(留余量给日志、模块、临时文件等);
示例安全配比(2G 内存、200K/进程):
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 2048 # ≤ 65536 ÷ 32 ≈ 安全值
MaxRequestsPerChild 0
</IfModule>Event/Worker 模式(线程复用,更省 fd)
- 一个子进程内多个线程共享部分文件句柄(如监听 socket),但每个请求仍可能打开新文件(如 PHP include、log write);
- 同样需要足够
nofile,但总需求低于 prefork; - 可设更高
MaxRequestWorkers,例如:<IfModule mpm_event_module> StartServers 3 MinSpareThreads 25 MaxSpareThreads 75 ThreadsPerChild 25 MaxRequestWorkers 4000 # 160 子进程 × 25 线程,总 fd 需 ≥ 65536 MaxConnectionsPerChild 0 </IfModule>
验证与监控
- 重启后再次检查进程 limits:
cat /proc/$(pgrep httpd | head -1)/limits | grep "open files"
- 观察错误日志是否还有
EMFILE(Too many open files):sudo tail -f /var/log/httpd/error_log | grep EMFILE
- 实时统计已打开文件数:
sudo lsof -p $(pgrep httpd | head -1) | wc -l
不复杂但容易忽略


















