For #3607, #4078, #4170, Datasource pool configuration can be configured. (#4178)

* For #3607, #4078, #4170, Datasource pool configuration.

* Fix ci error.
This commit is contained in:
杨翊 SionYang 2020-11-09 20:18:27 +08:00 committed by GitHub
parent cf92d19d03
commit 6b7fb05601
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 201 additions and 101 deletions

View File

@ -0,0 +1,84 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.service.datasource;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.Environment;
import java.util.concurrent.TimeUnit;
/**
* DataSource pool properties.
*
* <p>Nacos server use HikariCP as the datasource pool. So the basic pool properties will based on {@link
* com.zaxxer.hikari.HikariDataSource}.
*
* @author xiweng.yy
*/
public class DataSourcePoolProperties {
public static final long DEFAULT_CONNECTION_TIMEOUT = TimeUnit.SECONDS.toMillis(30L);
public static final long DEFAULT_VALIDATION_TIMEOUT = TimeUnit.SECONDS.toMillis(10L);
public static final int DEFAULT_MAX_POOL_SIZE = 20;
public static final int DEFAULT_MINIMUM_IDLE = 2;
private final HikariDataSource dataSource;
private DataSourcePoolProperties() {
dataSource = new HikariDataSource();
dataSource.setConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT);
dataSource.setValidationTimeout(DEFAULT_VALIDATION_TIMEOUT);
dataSource.setMaximumPoolSize(DEFAULT_MAX_POOL_SIZE);
dataSource.setMinimumIdle(DEFAULT_MINIMUM_IDLE);
}
/**
* Build new Hikari config.
*
* @return new hikari config
*/
public static DataSourcePoolProperties build(Environment environment) {
DataSourcePoolProperties result = new DataSourcePoolProperties();
Binder.get(environment).bind("db.pool.config", Bindable.ofInstance(result.getDataSource()));
return result;
}
public void setDriverClassName(final String driverClassName) {
dataSource.setDriverClassName(driverClassName);
}
public void setJdbcUrl(final String jdbcUrl) {
dataSource.setJdbcUrl(jdbcUrl);
}
public void setUsername(final String username) {
dataSource.setUsername(username);
}
public void setPassword(final String password) {
dataSource.setPassword(password);
}
public HikariDataSource getDataSource() {
return dataSource;
}
}

View File

@ -13,20 +13,18 @@
package com.alibaba.nacos.config.server.service.datasource;
import static com.alibaba.nacos.common.utils.CollectionUtils.getOrDefault;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import com.google.common.base.Preconditions;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.core.env.Environment;
import com.google.common.base.Preconditions;
import com.zaxxer.hikari.HikariDataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static com.alibaba.nacos.common.utils.CollectionUtils.getOrDefault;
/**
* Properties of external DataSource.
@ -37,15 +35,7 @@ public class ExternalDataSourceProperties {
private static final String JDBC_DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
public static final long CONNECTION_TIMEOUT_MS = 3000L;
public static final long VALIDATION_TIMEOUT = 10L;
public static final String TEST_QUERY = "SELECT 1 FROM dual";
public static final int DEFAULT_MAX_POOL_SIZE = 20;
public static final int DEFAULT_MINIMUM_IDLE = 20;
private static final String TEST_QUERY = "SELECT 1";
private Integer num;
@ -55,10 +45,6 @@ public class ExternalDataSourceProperties {
private List<String> password = new ArrayList<>();
private List<Integer> maxPoolSize = new ArrayList<>();
private List<Integer> minIdle = new ArrayList<>();
public void setNum(Integer num) {
this.num = num;
}
@ -75,14 +61,6 @@ public class ExternalDataSourceProperties {
this.password = password;
}
public void setMaxPoolSize(List<Integer> maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public void setMinIdle(List<Integer> minIdle) {
this.minIdle = minIdle;
}
/**
* Build serveral HikariDataSource.
*
@ -99,16 +77,12 @@ public class ExternalDataSourceProperties {
for (int index = 0; index < num; index++) {
int currentSize = index + 1;
Preconditions.checkArgument(url.size() >= currentSize, "db.url.%s is null", index);
HikariDataSource ds = new HikariDataSource();
ds.setDriverClassName(JDBC_DRIVER_NAME);
ds.setJdbcUrl(url.get(index).trim());
ds.setUsername(getOrDefault(user, index, user.get(0)).trim());
ds.setPassword(getOrDefault(password, index, password.get(0)).trim());
ds.setConnectionTimeout(CONNECTION_TIMEOUT_MS);
ds.setMaximumPoolSize(getOrDefault(maxPoolSize, index, DEFAULT_MAX_POOL_SIZE));
ds.setMinimumIdle(getOrDefault(minIdle, index, DEFAULT_MINIMUM_IDLE));
// Check the connection pool every 10 minutes
ds.setValidationTimeout(TimeUnit.MINUTES.toMillis(VALIDATION_TIMEOUT));
DataSourcePoolProperties poolProperties = DataSourcePoolProperties.build(environment);
poolProperties.setDriverClassName(JDBC_DRIVER_NAME);
poolProperties.setJdbcUrl(url.get(index).trim());
poolProperties.setUsername(getOrDefault(user, index, user.get(0)).trim());
poolProperties.setPassword(getOrDefault(password, index, password.get(0)).trim());
HikariDataSource ds = poolProperties.getDataSource();
ds.setConnectionTestQuery(TEST_QUERY);
dataSources.add(ds);
callback.accept(ds);

View File

@ -16,33 +16,29 @@
package com.alibaba.nacos.config.server.service.datasource;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.CONFIG_INFO4BETA_ROW_MAPPER;
import static com.alibaba.nacos.config.server.utils.LogUtil.DEFAULT_LOG;
import static com.alibaba.nacos.config.server.utils.LogUtil.FATAL_LOG;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.sql.DataSource;
import com.alibaba.nacos.common.utils.IPUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import com.alibaba.nacos.common.utils.ConvertUtils;
import com.alibaba.nacos.common.utils.IPUtil;
import com.alibaba.nacos.common.utils.StringUtils;
import com.alibaba.nacos.config.server.monitor.MetricsMonitor;
import com.alibaba.nacos.config.server.utils.ConfigExecutor;
import com.alibaba.nacos.config.server.utils.PropertyUtil;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.CONFIG_INFO4BETA_ROW_MAPPER;
import static com.alibaba.nacos.config.server.utils.LogUtil.DEFAULT_LOG;
import static com.alibaba.nacos.config.server.utils.LogUtil.FATAL_LOG;
/**
* Base data source.
@ -51,10 +47,6 @@ import com.zaxxer.hikari.HikariDataSource;
*/
public class ExternalDataSourceServiceImpl implements DataSourceService {
private static final Logger LOGGER = LoggerFactory.getLogger(ExternalDataSourceServiceImpl.class);
private static final String JDBC_DRIVER_NAME = "com.mysql.cj.jdbc.Driver";
/**
* JDBC execute timeout value, unit:second.
*/
@ -198,10 +190,6 @@ public class ExternalDataSourceServiceImpl implements DataSourceService {
return "UP";
}
static String defaultIfNull(String value, String defaultValue) {
return null == value ? defaultValue : value;
}
class SelectMasterTask implements Runnable {
@Override

View File

@ -24,7 +24,13 @@ import com.alibaba.nacos.config.server.utils.PropertyUtil;
import com.alibaba.nacos.sys.utils.ApplicationUtils;
import com.alibaba.nacos.sys.utils.DiskUtils;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
@ -36,13 +42,6 @@ import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;
/**
* local data source.
@ -145,14 +144,12 @@ public class LocalDataSourceServiceImpl implements DataSourceService {
}
private synchronized void initialize(String jdbcUrl) {
HikariDataSource ds = new HikariDataSource();
ds.setDriverClassName(jdbcDriverName);
ds.setJdbcUrl(jdbcUrl);
ds.setUsername(userName);
ds.setPassword(password);
ds.setIdleTimeout(30_000L);
ds.setMaximumPoolSize(80);
ds.setConnectionTimeout(10000L);
DataSourcePoolProperties poolProperties = DataSourcePoolProperties.build(ApplicationUtils.getEnvironment());
poolProperties.setDriverClassName(jdbcDriverName);
poolProperties.setJdbcUrl(jdbcUrl);
poolProperties.setUsername(userName);
poolProperties.setPassword(password);
HikariDataSource ds = poolProperties.getDataSource();
DataSourceTransactionManager tm = new DataSourceTransactionManager();
tm.setDataSource(ds);
if (jdbcTemplateInit) {

View File

@ -0,0 +1,68 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.config.server.service.datasource;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.env.MockEnvironment;
import static org.junit.Assert.assertEquals;
public class DataSourcePoolPropertiesTest {
private static final String JDBC_URL = "jdbc:derby://127.0.0.1:3306/nacos_devtest?characterEncoding=utf8&serverTimezone=UTC";
private static final String JDBC_DRIVER_CLASS_NAME = "org.apache.derby.jdbc.EmbeddedDriver";
private static final String PASSWORD = "nacos";
private static final String USERNAME = "nacos_devtest";
private static final Long CONNECTION_TIMEOUT = 10000L;
private static final Integer MAX_POOL_SIZE = 50;
private MockEnvironment environment;
@Before
public void setUp() throws Exception {
environment = new MockEnvironment();
environment.setProperty("db.user", USERNAME);
environment.setProperty("db.password", PASSWORD);
environment.setProperty("db.pool.config.connectionTimeout", CONNECTION_TIMEOUT.toString());
environment.setProperty("db.pool.config.maximumPoolSize", MAX_POOL_SIZE.toString());
}
@Test
public void testBuild() {
DataSourcePoolProperties poolProperties = DataSourcePoolProperties.build(environment);
poolProperties.setJdbcUrl(JDBC_URL);
poolProperties.setDriverClassName(JDBC_DRIVER_CLASS_NAME);
poolProperties.setUsername(USERNAME);
poolProperties.setPassword(PASSWORD);
HikariDataSource actual = poolProperties.getDataSource();
assertEquals(JDBC_URL, actual.getJdbcUrl());
assertEquals(JDBC_DRIVER_CLASS_NAME, actual.getDriverClassName());
assertEquals(USERNAME, actual.getUsername());
assertEquals(PASSWORD, actual.getPassword());
assertEquals(CONNECTION_TIMEOUT.longValue(), actual.getConnectionTimeout());
assertEquals(DataSourcePoolProperties.DEFAULT_VALIDATION_TIMEOUT, actual.getValidationTimeout());
assertEquals(MAX_POOL_SIZE.intValue(), actual.getMaximumPoolSize());
assertEquals(DataSourcePoolProperties.DEFAULT_MINIMUM_IDLE, actual.getMinimumIdle());
}
}

View File

@ -107,7 +107,7 @@ public class ExternalDataSourcePropertiesTest {
environment.setProperty("db.url.0", JDBC_URL);
List<HikariDataSource> dataSources = new ExternalDataSourceProperties().build(environment, (dataSource -> {
dataSource.validate();
Assert.assertEquals(dataSource.getMinimumIdle(), ExternalDataSourceProperties.DEFAULT_MINIMUM_IDLE);
Assert.assertEquals(dataSource.getMinimumIdle(), DataSourcePoolProperties.DEFAULT_MINIMUM_IDLE);
}));
Assert.assertEquals(dataSources.size(), 1);
}

View File

@ -1,16 +0,0 @@
#
# Copyright 1999-2018 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

View File

@ -40,6 +40,11 @@ server.port=8848
# db.user=nacos
# db.password=nacos
### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
#*************** Naming Module Related Configurations ***************#
### Data dispatch task execution period in milliseconds: