2

Web アプリケーションのストレス テスト中に、Hibernateがデータベースへの接続を作成できなくなったようです。

Web アプリケーションは、 Spring 3.0、Hibernate 3.6、および c3p0 0.9.2.1 接続プーリングを使用して開発されています。Tomcat 7で動作します。DBMS は MySQL Server 5.5 です。すべてのトランザクションは、@Transactionalアノテーションを介して Spring によって管理されます。

以下は、Hibernate/c3p0 の設定の一部です。

    <property name="acquireIncrement" value="5" />
    <property name="initialPoolSize" value="15" />
    <property name="minPoolSize" value="10" />
    <property name="maxPoolSize" value="75" />
    <property name="maxStatements" value="100" /> 
    <property name="maxIdleTime" value="600" />   
    <property name="checkoutTimeout" value="2500" /> 
    <property name="autoCommitOnClose" value="true" />
    <bean id="transactionManager"
      class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />      
    <property name="defaultTimeout" value="15" />
    </bean>

これは JDBC 接続 URL です。

jdbc.url=jdbc:mysql://myserver:myport/mydb?connectTimeout=31000&socketTimeout=30000

同時ユーザー数が約 200 になると、CPU 負荷が 100% 近くになり (ただし、接続プールはまだ 75 未満のようです)、次の例外が発生します。

 SEVERE: Cannot connect to database.
 org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransa
 ctionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.exception.GenericJDBCException: Cannot open connec
 tion
         at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
         at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
         at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
         at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
         at com.my-company.SimpleConnetionLogFilter.doFilter(SimpleConnetionLogFilter.java:132)
         at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
         at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
         at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
         at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
         at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
         at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
         at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
         at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
         at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
         at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
         at org.apache.coyote.ajp.AjpProcessor.process(AjpProcessor.java:200)
         at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
         at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
         at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
         at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
         at java.lang.Thread.run(Unknown Source)
 Caused by: org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org
 .hibernate.exception.GenericJDBCException: Cannot open connection
         at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:596)
         at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
         at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
         at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
         at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
         at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
         at com.my-company.bizlogic.spring.XService$$EnhancerByCGLIB$$4e6a04f7.digest(<generated>)
         at com.my-company.XController.handleRequest(XController.java:55)
         at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
         at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
         at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
         at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
         ... 24 more
 Caused by: org.hibernate.exception.GenericJDBCException: Cannot open connection
         at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140)
         at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128)
         at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
         at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52)
         at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:449)
         at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
         at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:160)
         at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:81)
         at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:551)
         ... 35 more
 Caused by: java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
         at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
         at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77)
         at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:687)
         at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
         at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:81)
         at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
         ... 39 more
 Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@7624a28d -- timeout at awaitAvailable()
         at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1416)
         at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:606)
         at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:526)
         at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:755)
         at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:682)
         ... 42 more

プール内の 75 個の接続がすべて使用されるとどうなるか、まだはっきりとはわかりません。

次のトランザクションは 1 つの空き接続を待つことになると思いました。

そして、トランザクションのdefaultTimeoutを設定したので、この場合にこれが起こると予想していました。この種のエラーはアプリケーションで管理され、クライアントはサーバーがビジーであることを認識します。しかし現在、一般的な「サーバー内部エラー」が生成されています。これは、Tomcat 側では、ビジー状態であるだけでなく、MySQL に到達できなくなっているように見えるためです。

さらに、設定に何か不足していますか?すでに Hibernate/c3p0 および JDBC パラメータのいくつかを上げようとしましたが、唯一の効果は、常に JDBC 接続に関連する別の例外を取得することです。

4

2 に答える 2

3

アプリケーション (NON JTA) の単純な負荷テスト中に、同様の問題が発見されました。接続解放モードを変更し、これで問題が解決しました。それがあなたのためになることを願っています:

Hibernate プロパティ hibernate.connection.release_mode=after_transaction

于 2013-04-09T13:28:48.043 に答える
1

c3p0 パラメーターの checkoutTimeout が設定されていて、接続リークによってプールを使い果たしているか、プールを非常に強くプッシュしているため、一部のクライアントが checkoutTimeout 期間内に接続を取得できません。

対処方法:

1) 接続をリークしていないことを確認します。unreturnedConnectionTimeout と debugUnreturnedConnectionStackTraces を設定してみてください (こちらを参照)

2) 接続リークがない場合は、負荷を処理できるように DataSource をより適切に構成します。まず、numHelperThreadsを増やしてみて、実行しているコアの数よりも大幅に大きくしてください (これらのスレッドはデータベースの IO で頻繁に停止されるため)。次に、maxPoolSize を大きくしてみます。ステートメント プーリングを再構成することもできます。簡単にするために、この問題を解決するまでオフにします (maxStatements をゼロに設定します)。接続プーリングがうまく機能している場合は、それをオンに戻すことができますが、100 のステートメントは 200 程度の接続を処理するのにほとんどありません。maxStatementsPerConnection の使用を検討してくださいmaxStatements の代わりに。その値を、アプリケーション クライアントによって頻繁に使用される PreparedStatements の数に設定します。

3) それでも DataSource が負荷をすぐに処理できない場合は、より長いcheckoutTimeoutを受け入れます(またはクライアントがタイムアウトしないように checkoutTimeout をゼロに設定します)。

関係ありません... autoCommitOnCloseを true に設定してもよろしいですか?

幸運を!

于 2013-04-09T12:00:31.307 に答える