
Apache(通常指 Apache HTTP Server)本身是 C 语言编写的 Web 服务器,不直接运行 Java 字节码;你提到的“Java 中 Apache”大概率是指基于 Java 的 Apache Tomcat(常被简称为 “Apache Tomcat”),或项目中同时使用了 Apache HTTP Server 作为反向代理 + Tomcat 作为应用服务器的架构。高并发下出现的“文件描述符限制”问题,本质是操作系统对单个进程可打开文件数(包括 socket、日志文件、配置文件等)的硬性约束,而非 Java 或 Tomcat 自身的缺陷。解决需从系统层、JVM 层、Tomcat 配置三方面协同优化。
检查并提升操作系统的文件描述符限制
Linux 默认的 ulimit -n 通常为 1024,远低于高并发场景需求(如 5000+ 并发连接)。必须调整:
临时生效:执行 ulimit -n 65536(仅当前 shell 有效) 永久生效:修改 /etc/security/limits.conf,添加两行:tomcat soft nofile 65536tomcat hard nofile 65536 (假设 Tomcat 以用户 tomcat 运行;若用 root 启动,改用 root) 确保 systemd 启动时加载限制:若用 systemctl 管理(如 /usr/lib/systemd/system/tomcat.service),在 [Service] 段添加:LimitNOFILE=65536
优化 Tomcat 的连接器(Connector)配置
Tomcat 的 server.xml 中的 <Connector> 决定网络连接行为。避免盲目调大 maxConnections/maxThreads,而应结合实际负载与 FD 消耗逻辑:
禁用不必要的协议:如关闭 AJP 连接器(除非真用 Apache httpd 做反代),减少一个监听端口即节省一个 FD 合理设置 acceptCount:该值是等待队列长度,不占用 FD,但设过大易积压请求;建议 ≤ 100 启用 connectionTimeout:例如 connectionTimeout=”20000″,及时释放空闲连接,防止 FD 被长连接占满 若用 NIO/NIO2(推荐),确认 protocol=”org.apache.coyote.http11.Http11NioProtocol”,它比 BIO 更省线程和 FD
排查 Java 应用自身导致的 FD 泄漏
Tomcat 只是容器,真正的 FD 消耗大户常是应用代码:
立即学习“Java免费学习笔记(深入)”;
未关闭的流/资源:InputStream、OutputStream、Socket、FileChannel、数据库连接(Connection/Statement/ResultSet)等,务必用 try-with-resources 或 finally 显式 close HTTP 客户端未复用连接:如用 HttpURLConnection 或 OkHttp 时未配置连接池(OkHttp 的 ConnectionPool、Apache HttpClient 的 PoolingHttpClientConnectionManager),每次请求新建 socket,极易耗尽 FD 使用 lsof -p <pid> | wc -l 实时查看 Tomcat 进程打开的 FD 数量;配合 lsof -p <pid> -i 筛选网络连接,观察是否存在大量 TIME_WAIT 或 CLOSE_WAIT 状态连接(可能说明连接未正常关闭或对端异常)
补充建议:监控与验证
光调参不验证等于没做:
启动后检查 Tomcat 日志是否报 java.io.IOException: Too many open files 用 cat /proc/<pid>/limits | grep “Max open files” 确认进程级限制已生效 压力测试时,用 watch -n 1 ‘lsof -p <pid> | wc -l’ 观察 FD 数是否稳定增长后回落(健康状态),还是持续攀升至上限(存在泄漏) 考虑接入 Prometheus + JMX Exporter,监控 Catalina:type=ThreadPool,name=”http-nio-8080″ 下的 currentThreadCount 和 maxThreads,辅助判断线程与连接是否匹配

评论(0)