Liquibase in Spring boot application keeps 10 connections open

北城余情 提交于 2021-02-11 07:21:05

问题


I'm working on a Spring Boot application with Liquibase integration to setup the database. We use a different user for the database changes which we configured using the application.properties file

liquibase.user=abc
liquibase.password=xyz
liquibase.url=jdbc:postgresql://something.eu-west-1.rds.amazonaws.com:5432/app?ApplicationName=${appName}-liquibase
liquibase.enabled=true
liquibase.contexts=dev,postgres

We have at this moment 3 different microservices in deployment and we noticed that for every running instance, Liquibase opens 10 connections and it never closes these connections unless we stop the application. This basically means that in development we regularly hit the connection limit of our Amazon RDS instance.

Right now, in development, 40 of 74 active connections are occupied by Liquibase. If we ever want to go to production with this, having autoscaling enabled for all the microservices, that would mean we'll have to over-scale the database in order not to hit any connection limits.

Is there a way to

  • tell liquibase to not use a connection pool of 10 connections
  • tell liquibase to stop or close the connections

So far I found no documentation on how to do this.


回答1:


Thanks to the response of Slava I managed to fix the problem with following datasource configuration class

@Configuration
public class LiquibaseDataSourceConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(LiquibaseDataSourceConfiguration.class);

    @Autowired
    private LiquibaseDataSourceProperties liquibaseDataSourceProperties;

    @LiquibaseDataSource
    @Bean
    public DataSource liquibaseDataSource() {
        DataSource ds =  DataSourceBuilder.create()
                .username(liquibaseDataSourceProperties.getUser())
                .password(liquibaseDataSourceProperties.getPassword())
                .url(liquibaseDataSourceProperties.getUrl())
                .driverClassName(liquibaseDataSourceProperties.getDriver())
                .build();
        if (ds instanceof org.apache.tomcat.jdbc.pool.DataSource) {
            ((org.apache.tomcat.jdbc.pool.DataSource) ds).setInitialSize(1);
            ((org.apache.tomcat.jdbc.pool.DataSource) ds).setMaxActive(2);
            ((org.apache.tomcat.jdbc.pool.DataSource) ds).setMaxAge(1000);
            ((org.apache.tomcat.jdbc.pool.DataSource) ds).setMinIdle(0);
            ((org.apache.tomcat.jdbc.pool.DataSource) ds).setMinEvictableIdleTimeMillis(60000);
        } else {
            // warnings or exceptions, whatever you prefer
        }

        LOG.info("Initialized a datasource for {}", liquibaseDataSourceProperties.getUrl());
        return ds;
    }

}

The documentation of the properties can be found on the site of Tomcat: https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html

  • initialSize: The initial number of connections that are created when the pool is started
  • maxActive: The maximum number of active connections that can be allocated from this pool at the same time
  • minIdle: The minimum number of established connections that should be kept in the pool at all times
  • maxAge: Time in milliseconds to keep this connection. When a connection is returned to the pool, the pool will check to see if the now - time-when-connected > maxAge has been reached, and if so, it closes the connection rather than returning it to the pool. The default value is 0, which implies that connections will be left open and no age check will be done upon returning the connection to the pool.
  • minEvictableIdleTimeMillis: The minimum amount of time an object may sit idle in the pool before it is eligible for eviction.

So it does not appear to be a connection leak, it's just the default configuration of the datasource which is not optimal for Liquibase if you use a dedicated datasource. I don't expect this to be a problem if the liquibase datasource is your primary datasource.




回答2:


This change to connection pool management was introduced in Spring Boot version 2.0.6.RELEASE, and only takes effect if you use Spring Boot Actuator. There is an actuator endpoint (enabled by default) which allows you to get change sets applied by Liquibase. For this to work Liquibase keeps its database connections open. You can disable the endpoint with management.endpoint.liquibase.enabled = false, in which case the connection pool used by Liquibase will be shutdown after the initial run.

  • GitHub issue related to this change: https://github.com/spring-projects/spring-boot/issues/13832
  • Spring Boot Actuator (see 12. Liquibase: https://docs.spring.io/spring-boot/docs/2.0.6.RELEASE/actuator-api/html/



回答3:


I don't know why liquibase doesn't close a connection, maybe it's a bug and you should create an issue for that.

To set connection pool for liquibase you have to create a custom data source and mark it with @LiquibaseDataSource annotation.

Related issues provide more details:

  • Possibility to specify custom dataSource configuration for liquibase only
  • Add LiquibaseDataSource annotation


来源:https://stackoverflow.com/questions/41636250/liquibase-in-spring-boot-application-keeps-10-connections-open

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!