Поток потоков в приложении Tomcat java - все потоки в ОЖИДАНИИ для c3p0 BasicResourcePool.awaitAvailable - PullRequest
0 голосов
/ 17 февраля 2020

наше java веб-приложение в настоящее время испытывает случайные (и никогда ранее не возникавшие) проблемы с блоками, вызванные внезапным всплеском созданных потоков и последующим исчерпанием максимального количества потоков, которое может создать Tomcat (по умолчанию = 200) .

Последний всплеск привел к созданию 120 новых потоков за 10 минут с счетом от 80 до 200 и блокированием приложения. Обычный счетчик потоков равен 70-80.

При выполнении дампа потока все эти потоки находятся в состоянии WAITING и, похоже, все ожидают нового соединения с СУБД от c3p0.

Это пример стека:

"http-nio-8443-exec-77  Waiting Thread ID: 10016","1"

"java.lang.Object.wait(long)","2"
"com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(long) BasicResourcePool.java:1414","2"
"com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(long) BasicResourcePool.java:606","2"
"com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(long) BasicResourcePool.java:526","2"
"com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse() C3P0PooledConnectionPool.java:755","2"
"com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection() C3P0PooledConnectionPool.java:682","2"
"com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection() AbstractPoolBackedDataSource.java:140","2"
"org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.getConnection() AbstractRoutingDataSource.java:164","2"
"org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection() DatasourceConnectionProviderImpl.java:139","2"
"org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection() AbstractSessionImpl.java:380","2"
"org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection() LogicalConnectionImpl.java:228","2"
"org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection() LogicalConnectionImpl.java:171","2"
"org.hibernate.internal.SessionImpl.connection() SessionImpl.java:450","2"
"org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(Object, TransactionDefinition) HibernateTransactionManager.java:450","2"
"org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(TransactionDefinition) AbstractPlatformTransactionManager.java:373","2"
"org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(PlatformTransactionManager, TransactionAttribute, String) TransactionAspectSupport.java:463","2"
"org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(Method, Class, TransactionAspectSupport$InvocationCallback) TransactionAspectSupport.java:276","2"
"org.springframework.transaction.interceptor.TransactionInterceptor.invoke(MethodInvocation) TransactionInterceptor.java:96","2"
"org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() ReflectiveMethodInvocation.java:179","2"
"org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(MethodInvocation) ExposeInvocationInterceptor.java:92","2"
"org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() ReflectiveMethodInvocation.java:179","2"
"org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) CglibAopProxy.java:653","2"

Это наша конфигурация c3p0 для этого DataSource:

<property name="maxIdleTime" value="600" />
<property name="maxPoolSize" value="300" />
<property name="maxStatements" value="200" />
<property name="maxStatementsPerConnection" value="10" />
<property name="minPoolSize" value="15" />
<property name="idleConnectionTestPeriod" value="100" />
<property name="acquireIncrement" value="3" />
<property name="numHelperThreads" value="20" />

В настоящее время я пытаюсь добавить параметр тайм-аута, чтобы помочь мне отладить эти случаи

<property name="checkoutTimeout" value="30" />

Я читал, что должен использовать debugUnreturnedConnectionStackTraces и unreturnedConnectionTimeout для устранения таких проблем, но в настоящее время я не очень хорошо их понимаю и боюсь чтобы использовать их в производстве.

Есть ли другой тип конфигурации, который я мог бы попытаться помочь мне решить проблему? Некоторые другие настройки тайм-аута?

Стек:

  • СУБД: Sql Сервер 2014
  • c3p0: 0.9.2.1
  • Спящий режим: 4.3.5
  • Весна: 4.1.6

РЕДАКТИРОВАТЬ (ПРОВЕРИТЬ ПРОВЕРКУ ТАЙМ-АУТА)

Я попытался поставить в рассматриваемую базу данных параметр checkoutTimeout:

<property name="checkoutTimeout" value="30" />

Это свойство должно заставить все потоки, ожидающие извлечения соединения из c3p0, отказаться через 30 секунд в случае исчерпания пула, с исключение SqlException.

Не слишком после ввода этого свойства в производство мы начали регистрировать такие ошибки:

Caused by: org.hibernate.exception.GenericJDBCException: Could not open connection

    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)

    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)

    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:112)

    at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:235)

    at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:171)

    at org.hibernate.internal.SessionImpl.connection(SessionImpl.java:450)

    at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:450)

    ... 119 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.jdbc.datasource.lookup.AbstractRoutingDataSource.getConnection(AbstractRoutingDataSource.java:164)

    at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:139)

    at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:380)

    at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:228)

    ... 122 more

Caused by: com.mchange.v2.resourcepool.TimeoutException: A client timed out while waiting to acquire a resource from com.mchange.v2.resourcepool.BasicResourcePool@14e83e8f -- 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)

    ... 127 more

Так что я думаю, это доказательство того, что пул исчерпан ( maxPoolSize составляет 300). Это правильно?

РЕДАКТИРОВАТЬ 2: ВОПРОС РЕШЕН, СМОТРИТЕ НА МОЙ ОТВЕТ

Ответы [ 2 ]

0 голосов
/ 27 февраля 2020

Мы смогли решить эту проблему с помощью JMX и мониторинга состояния источников данных c3p0.

Использование JVisualVM (или вы также можете использовать JConsole, если у вас нет Oracle JDK ) мы посмотрели на состояние нашего источника данных, и это то, что было показано:

enter image description here

Наш размер пула равен 300, что означает, что может быть максимально 300 соединений доступны в любой момент времени c3p0, и уже 95 были заняты, и это число росло.

С небольшим количеством проб и ошибок, зная, что эта проблема возникла только у конкретного клиента, мы начали тестировать новые функции, которые использовал этот клиент (проблема возникла только недавно), и мы нашли конкретный вариант использования, используя с, мы повторили проблему, постоянно пропуская соединения.

В кодовой базе проблема заключалась в том, что этот вариант использования открыл сеанс bnut никогда не позаботился о его закрытии.

Это было примерно так:

this.sessionFactory.withOptions().noInterceptor().openSession();

Мы добавили закрытие сессии и Проблема была решена :

session.flush();
session.close();
0 голосов
/ 17 февраля 2020

Вы можете попросить ваших Sql администраторов серверов предоставить некоторую статистику c относительно количества видений, связанных с вашим приложением в течение определенного периода, времени, потраченного на выполнение SQL, et c.

...