我们在 Tomcat 中使用 JDBCRealm 和 mysql 进行表单认证。这几乎总是可以正常工作。
当我们停止/重新启动 mysql 数据库(在测试中)时,我们注意到其中一个 Tomcat HTTP 线程将无休止地等待一些与身份验证相关的数据,而不是失败(例如 IOException 或超时等)。这会导致所有其他 HTTP 线程也阻塞,只要它们需要共享同步方法。结果是创建了越来越多的 HTTP 线程,全部阻塞,直到达到最大值。
冻结的线程永远不会唤醒或超时,即使我使用 netstat 来确认它阻塞的连接实际上已经消失了。
双方之间有防火墙,尽管我认为这与这里的问题无关。连接是“正常”建立和断开的。
快速解决方案当然是使用数据库停止/启动 tomcat,但调用不会简单地失败似乎很奇怪。此外,我担心这会在类似情况下的生产中发生。
除了重启tomcat或手动杀死阻塞线程之外,我们还能做些什么吗?
提前感谢您的想法。
设置:
- tomcat6
- 用于表单认证的 JDBCRealm
- mysql 5.5 数据库
- mysql-connector-java-5.1.7-bin.jar
server.xml 的相关部分:
<Realm className="org.apache.catalina.realm.LockOutRealm" lockOutTime="300">
<Realm className="org.apache.catalina.realm.JDBCRealm"
connectionName="xxx"
connectionPassword="xxx"
connectionURL="jdbc:mysql://xxx:6446/xxx?autoReconnect=true"
digest="xxx"
driverName="com.mysql.jdbc.Driver"
roleNameCol="xxx"
userCredCol="xxx"
userNameCol="xxx"
userRoleTable="xxx"
userTable="xxx"
maxActive="30"
maxIdle="30"
maxWait="10000"
factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"/>
</Realm>
阻塞线程的示例(阻塞“同步”方法的入口):
Name: http-8080-60
State: BLOCKED on org.apache.catalina.realm.JDBCRealm@edeb18b owned by: http-8080-61
Total blocked: 27 Total waited: 63
Stack trace:
org.apache.catalina.realm.JDBCRealm.authenticate(JDBCRealm.java:353)
org.apache.catalina.realm.CombinedRealm.authenticate(CombinedRealm.java:178)
org.apache.catalina.realm.LockOutRealm.authenticate(LockOutRealm.java:196)
org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:260)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:454)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:394)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
java.lang.Thread.run(Unknown Source)
导致所有其他线程阻塞的单个线程(请注意,“available()”调用正在等待/阻塞不再存在的连接):
Name: http-8080-61
State: RUNNABLE
Total blocked: 132 Total waited: 1,198
Stack trace:
java.net.PlainSocketImpl.socketAvailable(Native Method)
java.net.PlainSocketImpl.available(Unknown Source)
- locked java.net.SocksSocketImpl@c679aa4
java.net.SocketInputStream.available(Unknown Source)
com.mysql.jdbc.util.ReadAheadInputStream.available(ReadAheadInputStream.java:231)
com.mysql.jdbc.MysqlIO.clearInputStream(MysqlIO.java:941)
com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1887)
com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2101)
com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2548)
- locked java.lang.Object@65d98b58
com.mysql.jdbc.ConnectionImpl.commit(ConnectionImpl.java:1560)
- locked java.lang.Object@65d98b58
org.apache.catalina.realm.JDBCRealm.getPassword(JDBCRealm.java:583)
- locked org.apache.catalina.realm.JDBCRealm@edeb18b
org.apache.catalina.realm.JDBCRealm.authenticate(JDBCRealm.java:414)
- locked org.apache.catalina.realm.JDBCRealm@edeb18b
org.apache.catalina.realm.JDBCRealm.authenticate(JDBCRealm.java:361)
- locked org.apache.catalina.realm.JDBCRealm@edeb18b
org.apache.catalina.realm.CombinedRealm.authenticate(CombinedRealm.java:178)
org.apache.catalina.realm.LockOutRealm.authenticate(LockOutRealm.java:196)
org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:260)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:454)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:394)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
java.lang.Thread.run(Unknown Source)