Apache Tomcat 9.0.26 加载tomcat-users.xml报打开文件过多异常求助
问题原因分析
- 你对报错的指向存在认知偏差:异常中出现tomcat-users.xml路径不代表该文件本身有问题,本质是Tomcat进程的文件句柄总占用量已经触达系统设置的4096上限,此时恰好触发了Tomcat后台定时刷新用户配置文件的任务,所以才会在打开该文件时报错。后续日志中出现的socket连接报错也可以佐证是全局文件句柄耗尽,而非单个文件的问题。
- 你的当前配置中UserDatabase默认是可写状态,Tomcat会定期后台重新读取tomcat-users.xml检查更新,频繁打开文件会增加句柄消耗,部分旧版本Tomcat的MemoryUserDatabase组件还存在句柄泄漏的已知问题,会加快句柄占用的上涨速度。
- 4096的文件句柄上限对于生产环境运行的Tomcat来说普遍偏低,HTTP连接、加载的Jar包、临时文件、业务代码打开的资源都会占用文件句柄,流量稍高就容易触达上限。
可行解决方案
- 先确认句柄占用情况:执行
ps -ef | grep tomcat获取Tomcat进程PID,再执行lsof -p <替换为实际PID> | wc -l查看当前进程实际占用的句柄数,确认是否确实触达4096上限,排除文件权限类问题。 - 优化UserDatabase配置:在现有GlobalNamingResources的Resource配置中新增
readonly="true"属性,修改后配置如下:
<GlobalNamingResources> <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users --> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" readonly="true" /> </GlobalNamingResources>
配置后Tomcat仅会在启动时加载一次tomcat-users.xml,不会后台定时刷新,既减少不必要的句柄消耗,也可以规避对应组件的句柄泄漏问题。
- 合理调高文件句柄上限:建议根据业务规模将进程级文件句柄上限调整到65535或更高,需要同时修改/etc/security/limits.conf配置和Tomcat启动脚本中的ulimit设置,避免配置不生效。
- 排查业务代码泄漏:如果调整句柄上限后占用量仍快速上涨,可通过
lsof -p <PID>查看占比最高的句柄类型,排查业务代码是否存在文件流未关闭、网络连接未释放、第三方资源未回收等泄漏问题。 - 可选升级Tomcat版本:9.0.26属于较老的次版本,后续9.0.x分支已修复多个资源泄漏类bug,条件允许的情况下可以升级到最新的稳定版从底层规避问题。
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

