druid CommunicationsException with spring boot health check

goqiplq2  于 2021-11-27  发布在  Java
关注(0)|答案(1)|浏览(304)

Description

  • Database is MySql, and connection's lifetime is 5 minutes.
  • There are more idle connections in the low peak period of the business
  • Using Druid Jdbc Pool, the connection will be cleaned up for more than 3 minutes.
  • The monitoring system calls the health check every 1 minute.
public class DataSourceHealthIndicator extends AbstractHealthIndicator implements InitializingBean {
	private void doDataSourceHealthCheck(Health.Builder builder) throws Exception {
		String product = getProduct();
		builder.up().withDetail("database", product);
		String validationQuery = getValidationQuery(product);
		// execute validationQuery……
	 }

	private String getProduct() {
		return this.jdbcTemplate.execute((ConnectionCallback<String>) this::getProduct);
	}

	private String getProduct(Connection connection) throws SQLException {
		return connection.getMetaData().getDatabaseProductName();
	}
}

Exception analysis

The spring boot actuator gets the jdbc Connection when executing the DataSource health check, and calls connection.getMetaData().getDatabaseProductName(), which does not actually operate the database, resulting in the connection's effective time not being renewal.

When returning to the connection pool, Druid will change lastActiveTimeMillis to the latest time, which will cause the cleanup thread to mistake the connection for its validity, so it has not been cleaned up.

In fact, it has passed the survival time. It will disturb the cleanup of the connection pool, then the next time you get this connection, it will be invalid for MySql, throwing a CommunicationsException exception.

If I just get the connection from the connection pool and return it to the connection pool, nothing is done. This will also update the time of 'lastActiveTimeMillis', which will disturb the recycling thread to determine whether the connection is invalid or not.

相关问题