Загрузочное приложение Spring с ThreadPoolTaskExecutor теряет соединение с MySQL через определенное время - PullRequest
0 голосов
/ 14 февраля 2019

Проблема с устранением неполадок в существующем приложении Spring Boot.Где приложение настроено с 'ThreadPoolTaskExecutor'.И через некоторое время он теряет соединение с базой данных mysql, выдавая исключение «MySQLNonTransientConnectionException».

Пожалуйста, найдите следующие сведения о приложении, где я пытаюсь проанализировать проблему -

springBootVersion: 1.5.2 Версия Groovy: 2.3.9

  1. Настроены следующие компоненты в WebAppConfig.groovy
@Bean
HealthCheckRegistry healthCheckRegistry(@Qualifier("dataSource") DataSource rlOpDataSource) {
    def dBCheck = new BasicDatabaseCheck(dataSource, true)
    Map<String, HealthCheck> healthCheckMap = ["Database Check":dBCheck]
    HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry(healthCheckExecutor(), healthCheckMap)
    healthCheckRegistry
}

@Bean
AsyncTaskExecutor healthCheckExecutor() {
    ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor()
    threadPoolTaskExecutor.with {
        corePoolSize = Runtime.getRuntime().availableProcessors() * 2
        maxPoolSize = Integer.MAX_VALUE
        queueCapacity = Integer.MAX_VALUE
        keepAliveSeconds = 60
        allowCoreThreadTimeOut = true
    }
    threadPoolTaskExecutor.initialize()
    new ConcurrentTaskExecutor(threadPoolTaskExecutor)
}
Класс BasicDatabaseCheck имеет экземпляр JdbcTemplate
public class BasicDatabaseCheck  {
    private JdbcTemplate jdbcTemplate;

    public BasicDatabaseCheck(DataSource dataSource) {
        this(new JdbcTemplate(dataSource), isPrimary);
    }

    public HealthState execute() {
    ---(implementation which executes database queries using 
    JdbcTemplate)
    }
}
HealthCheckRegistry, который вызывает функцию BasicDatabaseCheck через AsyncTaskExecutor
HealthCheckRegistry class with :

    public class HealthCheckRegistry {

    private final AsyncTaskExecutor executor;

    public HealthCheckResults runHealthChecks{

    Future<HealthState> future = this.executor.submit(
    ----(implementation which calls BasicDatabaseCheck.execute function)
                });
} 

С этой конфигурацией приложение работает нормально.Выставили другие API, которые также работают без каких-либо исключений.Но через некоторое время приложение выдает следующую ошибку:

 WARN 24566 --- [ThreadPoolTaskExecutor-1] o.s.jdbc.support.SQLErrorCodesFactory    : Error while extracting database name - falling back to empty error codes

org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
    at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:342) ~[spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:366) ~[spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.support.SQLErrorCodesFactory.getErrorCodes(SQLErrorCodesFactory.java:212) ~[spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.setDataSource(SQLErrorCodeSQLExceptionTranslator.java:134) [spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.<init>(SQLErrorCodeSQLExceptionTranslator.java:97) [spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.support.JdbcAccessor.getExceptionTranslator(JdbcAccessor.java:99) [spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:419) [spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:474) [spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:484) [spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:494) [spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.queryForMap(JdbcTemplate.java:489) [spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at com.reachlocal.health.impl.BasicDatabaseCheck.execute(BasicDatabaseCheck.java:38) [core-2.0.jar!/:na]
    at com.reachlocal.health.HealthCheckRegistry$1.call(HealthCheckRegistry.java:139) [core-2.0.jar!/:na]
    at com.reachlocal.health.HealthCheckRegistry$1.call(HealthCheckRegistry.java:135) [core-2.0.jar!/:na]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_25]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_25]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_25]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_25]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408) ~[na:1.8.0_25]
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.Util.getInstance(Util.java:372) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:958) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:937) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:872) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.ConnectionImpl.throwConnectionClosedException(ConnectionImpl.java:1236) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.ConnectionImpl.checkClosed(ConnectionImpl.java:1231) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.ConnectionImpl.getMetaData(ConnectionImpl.java:2938) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.ConnectionImpl.getMetaData(ConnectionImpl.java:2933) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
    at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
    at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126) ~[tomcat-jdbc-8.5.11.jar!/:na]
    at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108) ~[tomcat-jdbc-8.5.11.jar!/:na]
    at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:81) ~[tomcat-jdbc-8.5.11.jar!/:na]
    at com.sun.proxy.$Proxy102.getMetaData(Unknown Source) ~[na:na]
    at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:331) ~[spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    ... 17 common frames omitted
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 4,825 milliseconds ago.  The last packet sent successfully to the server was 602 milliseconds ago.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_25]
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_25]
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_25]
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408) ~[na:1.8.0_25]
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1038) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3422) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3322) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3762) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2531) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2489) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1446) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:458) ~[spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:408) [spring-jdbc-4.3.7.RELEASE.jar!/:4.3.7.RELEASE]
    ... 11 common frames omitted
Caused by: java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:189) ~[na:1.8.0_25]
    at java.net.SocketInputStream.read(SocketInputStream.java:121) ~[na:1.8.0_25]
    at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:100) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:143) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:173) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2911) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3332) ~[mysql-connector-java-5.1.35.jar!/:5.1.35]
    ... 20 common frames omitted

Я попробовал следующие решения:

  1. Обновлен jar коннектора mysql с 5.1.6 до 5.1.35
  2. Одна из подозреваемых причин того, что mysql закрывает соединение с базой данных после идеальных часов более 8 (что по умолчанию).Поэтому я добавил одну функцию расписания, которая рекурсивно вызывает функцию execute из HealthCheckRegistry через каждые 1 час.После этого упомянутое исключение стало возникать непоследовательно.

Поэтому, пожалуйста, кто-нибудь может помочь мне решить проблему ..?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...