Весна, гибернация, стресс-тест MySQL
Во время стресс-тестирования моего веб-приложения, похоже, Hibernate больше не может создавать соединение с базой данных.
Веб-приложение разработано с использованиемSpring 3.0, Hibernate 3.6 и пула соединений c3p0 0.9.2.1. Он работает под Tomcat 7. СУБД-это MySQL Server 5.5. Все транзакции управляются Spring через аннотацию
@Transactional.Ниже приведены некоторые настройки 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 одновременных пользователей, загрузка процессора приближается к 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 соединений в пуле?
Я думал, что следующая транзакция будет ждать одного свободного соединения.
И поскольку я установил defaultTimeout для транзакций, я ожидал, что это произойдет в этот случай. Этот вид ошибки будет управляться в приложении, и клиент будет знать, что сервер занят. Но в настоящее время генерируется общая "внутренняя ошибка сервера", потому что на стороне Tomcat кажется, что MySQL больше не доступен, а не просто занят.
Кроме того, я что-то пропустил в настройках? Я уже пытался поднять некоторые параметры Hibernate/c3p0 и JDBC, но единственный эффект заключается в том, что я получаю другое исключение, всегда связанное с JDBC соединение.
2 ответов:
У вас установлен параметр c3p0 checkoutTimeout, и вы либо исчерпываете свои пулы через утечку соединения, либо просто очень сильно нажимаете на них, так что некоторые клиенты не могут получить соединение в течение периода checkoutTimeout.
Способы борьбы:
1) Убедитесь, что вы не пропускаете соединения. попробуйте установить unreturnedConnectionTimeout и debugUnreturnedConnectionStackTraces (см. здесь)2) если нет утечки соединения, настройте свой Источник данных лучше, так что он может иметь дело с вашей нагрузкой. Во-первых, попробуйте увеличить numHelperThreads, сделать значительно больше, чем количество ядер, на которых вы работаете (так как эти потоки часто задерживаются на IO с базой данных). Затем попробуйте увеличить maxPoolSize. Вы также можете перенастроить Объединение операторов. Для простоты я бы выключил его, пока вы не решите эту проблему (установите maxStatements в ноль). Когда пул соединений работает хорошо, вы можете включить его снова, но заявления о 100-это путь к немногим, чтобы справиться с 200-иш соединениями, вы будете непродуктивно сбивать через PreparedStatements. Рассмотрите возможность использования maxStatementsPerConnection вместо maxStatements. Установите его значение равным примерно числу подготовленных состояний, часто используемых клиентами приложений.
3) Если ваш источник данных все еще не может быстро обработать нагрузку, примите более длительный checkoutTimeout (или установите checkoutTimeout равным нулю, чтобы клиенты никогда не теряли время ожидания).Без связи... вы уверены вы хотите autoCommitOnClose установить в true?
Удачи!
Мы обнаружили аналогичную проблему во время простого нагрузочного теста нашего приложения (не JTA). Мы изменили режим выпуска соединения, и это решило нашу проблему. Надеюсь, что это делает для вас:
Свойство Hibernate зимовать.соединение.release_mode=after_transaction
Comments