一、连接池基本配置
- initialSize(初始化连接数)
根据应用的启动并发需求进行设置,通常建议设置为与minIdle相同的值,以确保应用启动时能够快速获取到数据库连接。
示例:initialSize=5 - minIdle(最小空闲连接数)
根据应用平时的最大QPS和响应时间(RT)来计算,确保在业务高峰期有足够的空闲连接可用。
示例:minIdle=10(具体值需根据实际情况调整) - maxActive(最大活跃连接数)
根据应用峰值时的QPS和RT来计算,同时考虑数据库服务器的负载能力。
示例:maxActive=50(具体值需根据实际情况调整) - maxWait(最大等待时间)
设置线程在获取数据库连接时的最大等待时间,以避免因等待时间过长而导致的业务超时。
示例:maxWait=3000(毫秒)
二、连接健康检查
- validationQuery(验证查询)
设置用于验证连接有效性的SQL语句。Druid提供了常用数据库的ValidConnectionChecker,如果数据库支持,则优先使用;否则,使用validationQuery。
示例:对于MySQL,validationQuery=SELECT 1 - testWhileIdle(空闲时检测)
建议设置为true,以在连接空闲时进行检测,确保连接的有效性。
示例:testWhileIdle=true - testOnBorrow(借出时检测)
设置为false,以减少借出连接时的开销。因为每次借出都进行检测会影响性能。
示例:testOnBorrow=false - testOnReturn(归还时检测)
设置为false,以避免归还连接时的额外开销。
示例:testOnReturn=false - timeBetweenEvictionRunsMillis(检测间隔时间)
设置触发空闲连接健康检查的间隔时间。
示例:timeBetweenEvictionRunsMillis=60000(毫秒) - minEvictableIdleTimeMillis(最小空闲时间)
设置连接在被清理前的最小空闲时间。
示例:minEvictableIdleTimeMillis=300000(毫秒)
三、性能监控与优化
- 启用监控统计功能
通过设置相关参数启用Druid的监控统计功能,以便实时监控连接池的使用情况和性能状况。
示例:在Druid配置中设置filters=stat来启用监控统计。 - 配置Web监控页面
启用Druid的Web监控页面,可以方便地查看连接池的运行状态、SQL执行次数、慢查询次数等关键指标。
示例:在Spring Boot应用中,可以通过配置druid.stat-view-servlet等参数来启用Web监控页面。 - 调整连接池参数
根据监控页面的数据和业务需求,不断调整连接池的参数,以达到最佳的性能表现。
示例:根据活跃连接数、等待连接数等指标,调整maxActive、minIdle等参数。
四、其他注意事项
- 连接泄露检测
启用连接泄露检测功能,可以及时发现并处理连接泄露问题。
示例:在Druid配置中设置removeAbandoned=true和removeAbandonedTimeout等参数。 - 日志记录
启用日志记录功能,可以记录SQL执行的时间、执行的SQL语句以及相关的异常信息,有助于问题的诊断和优化。
示例:在Druid配置中设置logAbandoned=true等参数。 - 安全性
确保Druid配置的安全性,避免敏感信息泄露。例如,不要将数据库密码等敏感信息硬编码在配置文件中。
五、使用时遇见的问题
- druid版本1.2.16,jdbc超时时间设置无效
初始化连接池时,会首先重jdbcUrl上获取超时配置,但这里是写死了 jdbcUrl.startsWith(“jdbc:mysql://”)。而如果使用了其他的jdbc就会导致获取不到,如:jdbc:mariadb。
当获取不到时,druid默认给设置成了10s,而对一些执行时间超10s的sql,则会被强制关闭。而且这个判断也存在错误,两个超时配置必须都配置socketTimeout才会生效。
public void init() throws SQLException {
...
if (this.jdbcUrl != null) {
this.jdbcUrl = this.jdbcUrl.trim();
initFromWrapDriverUrl();
initFromUrlOrProperties();
}
if (connectTimeout == 0) {
socketTimeout = DEFAULT_TIME_CONNECT_TIMEOUT_MILLIS;
}
if (socketTimeout == 0) {
socketTimeout = DEFAULT_TIME_SOCKET_TIMEOUT_MILLIS;
}
...
}
private void initFromUrlOrProperties() {
if (jdbcUrl.startsWith("jdbc:mysql://")) {
if (jdbcUrl.indexOf("connectTimeout=") != -1 || jdbcUrl.indexOf("socketTimeout=") != -1) {
String[] items = jdbcUrl.split("(\\?|&)");
for (int i = 0; i < items.length; i++) {
String item = items[i];
if (item.startsWith("connectTimeout=")) {
String strVal = item.substring("connectTimeout=".length());
setConnectTimeout(strVal);
} else if (item.startsWith("socketTimeout=")) {
String strVal = item.substring("socketTimeout=".length());
setSocketTimeout(strVal);
}
}
}
Object propertyConnectTimeout = connectProperties.get("connectTimeout");
if (propertyConnectTimeout instanceof String) {
setConnectTimeout((String) propertyConnectTimeout);
} else if (propertyConnectTimeout instanceof Number) {
setConnectTimeout(((Number) propertyConnectTimeout).intValue());
}
Object propertySocketTimeout = connectProperties.get("socketTimeout");
if (propertySocketTimeout instanceof String) {
setSocketTimeout((String) propertySocketTimeout);
} else if (propertySocketTimeout instanceof Number) {
setSocketTimeout(((Number) propertySocketTimeout).intValue());
}
}
}
- 数据库主备切换后,服务长时间无法恢复
数据库在切换时,如果服务中的数据库连接正好在执行sql,而sockettimeout未设置,导致这些连接一直是running状态,同时也无法被druid移除。如果进行并发测试,druid连接池拉满,导致后续的连接一直不可用。
解决方案:
JDBC URL 增加 connectTimeout 和 socketTimeout 配置
根据实际业务评估minIdle、maxActive 大小。