Отсутствие соединений в пуле соединений tomcat jdbc
Мы просто перешли из dbcp в пул соединений tomcat jdbc.
Мы попытались загрузить систему и получили следующее исключение:
java.sql.SQLException: [IA1856] Timeout: Pool empty. Unable to fetch a connection in 1 seconds, none available[size:125; busy:90; idle:0; lastwait:1000].
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:632)
at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:174)
at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:124)
at com.inneractive.model.mappings.BasicPersistenceEntityMapping.getConnection(BasicPersistenceEntityMapping.java:233)
at com.inneractive.model.mappings.BasicPersistenceEntityMapping.callWithConnection(BasicPersistenceEntityMapping.java:243)
at com.inneractive.model.mappings.PersistenceEntityMapping.get(PersistenceEntityMapping.java:194)
at com.inneractive.model.data.client.ClientUtils.GetClientByExamples(ClientUtils.java:353)
at com.inneractive.client.ExternalAdRingsClientStart.getClientInfoByRequestParametersOrInsert(ExternalAdRingsClientStart.java:1329)
at com.inneractive.client.ExternalAdRingsClientStart.newClientSession(ExternalAdRingsClientStart.java:245)
at com.inneractive.simpleM2M.web.SimpleM2MProtocolBean.generateCampaign(SimpleM2MProtocolBean.java:235)
at com.inneractive.simpleM2M.web.SimpleM2MProtocolBean.generateCampaign(SimpleM2MProtocolBean.java:219)
at com.inneractive.simpleM2M.web.AdsServlet.doGet(AdsServlet.java:175)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:555)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:396)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Обратите внимание:
[size:125; busy:90; idle:0; lastwait:1000]
Где соединения, которые не заняты?
После этого число занятых продолжало снижаться,
но мы до сих пор не смогли получить какие-либо соединения.
Любые идеи?
Конфигурация:
<Resource auth="Container" driverClassName="com.mysql.jdbc.Driver"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" loginTimeout="10000"
maxActive="35" maxIdle="35" maxWait="1000" name="jdbc/mysql"
password="-----" testOnBorrow="true" testOnReturn="false" type="javax.sql.DataSource"
url="jdbc:mysql://localhost:3306/my_db?elideSetAutoCommits=true&useDynamicCharsetInfo=false&rewriteBatchedStatements=true&useLocalSessionState=true&useLocalTransactionState=true&alwaysSendSetIsolation=false&cacheServerConfiguration=true&noAccessToProcedureBodies=true&useUnicode=true&characterEncoding=UTF-8"
username="root" validationQuery="SELECT 1"/>
env: ubuntu и tomcat 6. db - mysql
Ответы
Ответ 1
Взглянув на источник ConnectionPool.java, вы, кажется, попадаете в этот фрагмент кода в методе borrowConnection()
:
//we didn't get a connection, lets see if we timed out
if (con == null) {
if ((System.currentTimeMillis() - now) >= maxWait) {
throw new SQLException("[" + Thread.currentThread().getName()+"] " +
"Timeout: Pool empty. Unable to fetch a connection in " + (maxWait / 1000) +
" seconds, none available["+busy.size()+" in use].");
} else {
//no timeout, lets try again
continue;
}
}
Итак, в соответствии с этим ваше соединение Null.
Значение con
извлекается в строке:
PooledConnection con = idle.poll();
если вы отслеживаете код, вы увидите idle
(в зависимости от вашей конфигурации, но по умолчанию) FairBlockingQueue. Вы можете проверить реализацию для подсказок.
В общем, вам всегда нужно закрыть ResultSets, Statement и Connections, а используемые соединения должны быть правильно выпущены обратно в пул.
Неправильное выполнение может привести к тому, что соединения никогда не были закрыты = > никогда не будут снова доступны для повторного использования (утечки пула соединений).
Я предлагаю вам построить подробное ведение журнала по состоянию пула и контролировать его, чтобы изолировать проблему.
Некоторые рекомендации Apache для предотвращения утечек пула базы данных:
removeAbandoned="true"
удаленные подключения к базе данных удаляются и перерабатываются
removeAbandonedTimeout="60"
установить количество секунд, в течение которых соединение с базой данных простаивало до того, как оно считается заброшенным
logAbandoned="true"
зарегистрировать трассировку стека кода, который отказался от ресурсов подключения к базе данных. Имейте в виду, что "регистрация запрещенных подключений добавляет накладные расходы для каждого заимствования Connection, потому что необходимо создать трассировку стека".
Я все еще думаю немного увеличивая значение maxWait
(1200, 1500, 1700 - просто эксперимент, не будет разницы в времени отклика с точки зрения пользователя) очистят те редкие случаи, в которых у вас все еще есть проблемы.
Ответ 2
", где соединения, которые не заняты?
Похоже, что они были сброшены, и почему-то ваш пул соединений не пытается их повторно подключить.
Добавьте это к URL-адресу, к которому вы подключаетесь:
autoReconnect=true
И добавьте это как свойство ресурса, чтобы автоматически восстановить подключенные мертвые соединения.
validationQuery="SELECT 1"
Кроме того, это должно позволить вам видеть удаленные соединения:
logAbandoned="true"
Есть несколько похожих вопросов о переполнении стека.
Объединение пулов Tomcat, простоя подключений и создание соединений
Пул соединений JDBC не открывается повторно Соединения в tomcat
Однако также может быть, что вы не полностью освобождаете соединения, из-за которых они умирают.
Практика объединения соединений JDBC MySql во избежание исчерпанного пула соединений
Ответ 3
кажется ошибкой в пуле, переменная size
увеличивается, а затем пытается создать соединение,
но если создание терпит неудачу... у нас size
значение большое и никаких реальных подключений в пуле - ужасно:
//if we get here, see if we need to create one
//this is not 100% accurate since it doesn't use a shared
//atomic variable - a connection can become idle while we are creating
//a new connection
if (size.get() < getPoolProperties().getMaxActive()) {
//atomic duplicate check
if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
//if we got here, two threads passed through the first if
size.decrementAndGet();
} else {
//create a connection, we're below the limit
return createConnection(now, con, username, password);
}
} //end if