Apache高并发下“Too many open files”本质是fd耗尽,需从系统层、MPM配置、运行时泄漏三方面排查;最准fd统计应读/proc/PID/fd/;须在systemd unit中设LimitNOFILE并验证。

Apache 在高并发下触发 “Too many open files” 错误,本质是进程打开的 socket、日志文件、配置文件等资源未及时释放,叠加连接数激增导致 fd 耗尽。排查要从系统层、Apache 自身配置、运行时行为三方面入手,不能只调大限制了事。
查清 Apache 进程实际用了多少 fd
别依赖 lsof -p $(pgrep apache2 | head -1) | wc -l 这类粗略统计——它可能漏权限、含空行、重复计数。最准方式是直接读内核视图:
- 先找到主进程或一个 worker 进程 PID:
pgrep -f "apache2|httpd" - 查看该进程当前打开 fd 数量:
ls /proc/<pid>/fd/ 2>/dev/null | wc -l</pid> - 再确认它的上限:
cat /proc/<pid>/limits | grep "Max open files"</pid>,看软硬限制是否匹配预期
检查 Apache 的 MPM 模式与连接管理配置
Apache 的 fd 消耗和所用 MPM(prefork/event/work)强相关。event 模式虽轻量,但若 KeepAlive 时间过长或 MaxKeepAliveRequests 设得太高,仍会堆积大量空闲连接句柄:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
- 查当前启用的 MPM:
apachectl -V | grep MPM - 检查关键参数(通常在
/etc/apache2/mods-enabled/mpm_*.conf或httpd.conf):
•MaxRequestWorkers(旧版叫MaxClients):决定最大并发连接数,每连接至少占 1–2 个 fd
•KeepAliveTimeout:默认 5 秒,值越大,空闲连接句柄挂起越久
•MaxKeepAliveRequests:单连接复用次数,设为 0 表示不限,但会延长 fd 占用时间 - 如果用 prefork,每个子进程独占 fd 表,
MaxRequestWorkers × 每进程平均 fd 数很容易突破限制
定位 Apache 内部泄漏或异常打开行为
不是所有高 fd 都来自 HTTP 连接。常见“隐形消耗源”包括:
-
日志文件句柄未轮转关闭:访问日志(access.log)、错误日志(error.log)若用普通 FileLogger,logrotate 后 Apache 不自动 reopen,会继续往已删除文件写,同时保留旧 fd;建议改用
rotatelogs或 systemd-journald +CustomLog "|..."管道方式 - 模块加载过多:如 mod_php、mod_python 等嵌入式解释器,在请求中频繁 fopen/fsockopen 却未 fclose,尤其在异常分支或超时路径下
-
第三方模块或 CGI 脚本泄漏:用
lsof -p <pid> | awk '$5 ~ /^(REG|IPv4|IPv6|pipe)$/ {print $9}' | sort | uniq -c | sort -nr</pid>查看打开最多的文件路径和类型,重点盯/tmp、/var/log、localhost:port类 socket
验证并固化限制配置
Apache 服务由 systemd 启动时,/etc/security/limits.conf 对它无效。必须在 unit 文件里显式声明:
- 编辑:
sudo systemctl edit apache2.service(Debian/Ubuntu)或httpd.service(RHEL/CentOS) - 加入:
[Service]段下添加LimitNOFILE=65536 - 重载并重启:
sudo systemctl daemon-reload && sudo systemctl restart apache2 - 验证生效:
cat /proc/$(pgrep apache2 | head -1)/limits | grep "Max open files"

















