Ошибка таймаута подключения к MySQL - приложение Grails для Tomcat с использованием Hibernate и ORM
У меня есть небольшое приложение grails, работающее на Tomcat в Ubuntu на VPS. Я использую MySql в качестве своего хранилища данных, и все работает нормально, если я не выхожу из приложения более полудня (8 часов?). Я сделал несколько поисков и, по-видимому, это по умолчанию wait_timeout
в mysql.cnf, поэтому через 8 часов соединение будет умирать, но Tomcat не будет знать этого, когда следующий пользователь попытается просмотреть сайт, он увидит ошибку сбоя подключения. Обновление страницы исправит это, но я хочу полностью избавиться от ошибки. Для моей версии MySql (5.0.75) у меня есть только my.cnf, и он не содержит такого параметра. В любом случае изменение этого параметра не решит проблему.
Этот Сообщение в блоге, похоже, сообщает об аналогичной ошибке, но я до сих пор не совсем понимаю, что мне нужно настроить, чтобы получить это исправленное и также я надеюсь, что есть более простое решение, чем другая сторонняя библиотека. У машины, на которой я запущен, есть RAM 256 МБ, и я пытаюсь свести к минимуму количество программ/служб.
Есть ли что-то, что я могу настроить в Grails/Tomcat/MySql, чтобы уйти?
Спасибо заранее,
Гав
От моего Catalina.out;
2010-04-29 21:26:25,946 [http-8080-2] ERROR util.JDBCExceptionReporter - The last packet successfully received from the server was 102,906,722 milliseconds$
2010-04-29 21:26:25,994 [http-8080-2] ERROR errors.GrailsExceptionResolver - Broken pipe
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method)
...
2010-04-29 21:26:26,016 [http-8080-2] ERROR util.JDBCExceptionReporter - Already closed.
2010-04-29 21:26:26,016 [http-8080-2] ERROR util.JDBCExceptionReporter - Already closed.
2010-04-29 21:26:26,017 [http-8080-2] ERROR servlet.GrailsDispatcherServlet - HandlerInterceptor.afterCompletion threw exception
org.hibernate.exception.GenericJDBCException: Cannot release connection
at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.SQLException: Already closed.
at org.apache.commons.dbcp.PoolableConnection.close(PoolableConnection.java:84)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.close(PoolingDataSource.java:181)
... 1 more
Ответы
Ответ 1
Ссылаясь на статью у вас есть устаревшие подключения в пуле соединений DBCP, которые молча удаляются операционной системой или брандмауэром.
Решение состоит в том, чтобы определить запрос проверки и выполнить проверку работоспособности соединения до его фактического использования в приложении.
В grails это делается, изменяя файл grails-app/conf/ spring/Resource.groovy и добавляя следующее:
beans = {
dataSource(BasicDataSource) {
//run the evictor every 30 minutes and evict any connections older than 30 minutes.
minEvictableIdleTimeMillis=1800000
timeBetweenEvictionRunsMillis=1800000
numTestsPerEvictionRun=3
//test the connection while its idle, before borrow and return it
testOnBorrow=true
testWhileIdle=true
testOnReturn=true
validationQuery="SELECT 1"
}
}
Ответ 2
В grails 1.3.X вы можете изменить значения evictor в файле DataSource.groovy, чтобы убедиться, что объединенные соединения используются во время простоя. Это позволит убедиться, что сервер mysql не отключит соединение.
production {
dataSource {
pooled = true
// Other database parameters..
properties {
maxActive = 50
maxIdle = 25
minIdle = 5
initialSize = 5
minEvictableIdleTimeMillis = 1800000
timeBetweenEvictionRunsMillis = 1800000
maxWait = 10000
}
}
Быстрый способ проверить это - изменить файл MySQL my.cnf [mysql] и добавить параметр wait_time с низким значением.
Ответ 3
Попробуйте увеличить количество открытых подключений MySQL, поместив в DataSources.groovy следующее:
dataSource {
driverClassName = "com.mysql.jdbc.Driver"
pooled=true
maxActive=10
initialSize=5
// Remaining connection params
}
Если вы хотите пройти весь свиньи, попробуйте реализовать пул соединений; здесь полезная ссылка.
Ответ 4
Для grails 1.3.X мне пришлось добавить следующий код в Bootstrap.groovy:
def init = {servletContext ->
def ctx=servletContext.getAttribute(ApplicationAttributes.APPLICATION_CONTEXT)
//implement test on borrow
def dataSource = ctx.dataSource
dataSource.targetDataSource.setMinEvictableIdleTimeMillis(1000 * 60 * 30)
dataSource.targetDataSource.setTimeBetweenEvictionRunsMillis(1000 * 60 * 30)
dataSource.targetDataSource.setNumTestsPerEvictionRun(3)
dataSource.targetDataSource.setTestOnBorrow(true)
dataSource.targetDataSource.setTestWhileIdle(true)
dataSource.targetDataSource.setTestOnReturn(false)
dataSource.targetDataSource.setValidationQuery("SELECT 1")
}
Мне также пришлось импортировать org.codehaus.groovy.grails.commons.ApplicationAttributes
Ответ 5
Добавьте эти параметры в dataSource
testOnBorrow = true
testWhileIdle = true
testOnReturn = true
См. эту статью для получения дополнительной информации
http://sacharya.com/grails-dbcp-stale-connections/
Ответ 6
Начиная с grails 2.3.6 в конфигурации по умолчанию уже есть опции для предотвращения закрытия соединения с помощью тайм-аута
Это новые значения по умолчанию.
properties {
// See http://grails.org/doc/latest/guide/conf.html#dataSource for documentation
....
minIdle = 5
maxIdle = 25
maxWait = 10000
maxAge = 10 * 60000
timeBetweenEvictionRunsMillis = 5000
minEvictableIdleTimeMillis = 60000
validationQuery = "SELECT 1"
validationQueryTimeout = 3
validationInterval = 15000
testOnBorrow = true
testWhileIdle = true
testOnReturn = false
jdbcInterceptors = "ConnectionState;StatementCache(max=200)"
defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED
}
Ответ 7
Как выглядит ваша строка соединения JDBC? Вы можете установить параметр autoReconneect
в конфигурацию источника данных, например.
jdbc:mysql://hostname/mydb?autoReconnect=true