Java与Apache协同运行时FD耗尽的根因是多进程Apache子进程继承FD限制,叠加Tomcat高并发Socket、日志等开销突破默认上限;需系统级调优limits.conf、PAM配置,精调prefork与AJP连接池,并监控lsof及ss统计。
在java应用与apache通过mod_jk或mod_proxy配合运行时,若apache启用多进程模式(如prefork mpm),文件描述符(file descriptor, fd)耗尽是常见问题。根本原因在于每个apache子进程都会继承父进程的fd限制,而java后端(如tomcat)在高并发下频繁创建socket连接、日志文件句柄、临时文件等,容易突破系统默认的1024或4096上限,导致“too many open files”错误。
确认当前FD限制与实际使用量
先排查是否真为FD瓶颈:
- 查看Apache主进程的限制:cat /proc/$(pgrep -f 'httpd|apache' | head -1)/limits | grep "Max open files"
- 统计所有Apache进程打开的FD总数:lsof -p $(pgrep httpd | tr '\n' ',') 2>/dev/null | wc -l(注意去重和权限)
- 检查Java进程(如Tomcat):lsof -p $(jps -l | grep Bootstrap | awk '{print $1}') | wc -l
- 对比ulimit -n输出值与实际用量——若接近或超过,即为瓶颈
永久提升系统级FD限制
仅修改用户ulimit不够,Apache常以独立用户(如www-data、apache)运行,需系统级生效:
- 编辑/etc/security/limits.conf,添加两行(替换apache为实际运行用户):
apache soft nofile 65536
apache hard nofile 65536 - 确保/etc/pam.d/common-session(Debian/Ubuntu)或/etc/pam.d/login(RHEL/CentOS)包含:
session required pam_limits.so - 重启Apache服务使新限制生效(注意:需完全stop再start,reload可能不重读limits)
优化Apache与Java协同的FD占用
降低单请求FD消耗比盲目提限更可持续:
-
Apache端:在httpd.conf中调优prefork参数,避免进程过多:
StartServers 4
MinSpareServers 4
MaxSpareServers 12
MaxRequestWorkers 150(勿超系统总FD / 每进程平均FD) - 连接器配置:若用mod_jk,检查workers.properties中connection_pool_size和connection_pool_minsize,避免为每个请求新建连接;若用AJP,确认Tomcat的maxConnections与Apache并发匹配
- Java端:关闭Tomcat中未使用的Connector(如HTTP端口若只走AJP则禁用);检查应用代码是否泄漏InputStream/OutputStream、未关闭数据库连接、未释放NIO Channel
验证与监控
上线后必须持续观测:
立即学习“Java免费学习笔记(深入)”;
- 写简易脚本定期采集lsof -u apache | wc -l并告警(如超50000触发)
- 在Tomcat的server.xml中开启enableLookups="false"和connectionTimeout="20000",减少DNS解析和空闲连接占用
- 使用ss -s观察系统socket统计,重点关注TCP: time_wait数量——过多说明连接回收慢,可调net.ipv4.tcp_fin_timeout










