Druid连接池核心参数和保活机制
做Java后端开发,几乎所有人都用过Druid连接池。当然新版的SpringBoot默认了HikariCP,性能更高,对用户的配置参数更精简。 因为我们项目还在使用Druid,并且最近生产偶发报错 Communications link failure的问题。
在解决这个问题的过程中,也再次深入了解Druid的参数调优和保活机制,其实我们这个问题主要就是保活机制的参数设置问题。因此这里先以保活机制开头介绍,后边再介绍其他核心参数及其解决的问题。
遇到的问题
简单说:
- 流量低峰时,空闲连接被防火墙断开,变成僵死连接滞留在池中。获取连接执行sql时,报错 Communications link failure;
- 配置参数test-while-idle、validation-query 后,Communications link failure报错几乎没有了;但又出现了建立连接等待超时;
- 再配置 keep-alive、keep-alive-between-time-millis、time-between-eviction-runs-millis,彻底解决。
一、先纠正一个误区:Druid的保活机制
很多开发者一直以为:test-while-idle是后台探活、开了就能杜绝僵死连接。这是认识错误,也是线上偶发断连、获取连接超时的核心根源。
一开始设置了这个参数,报错是少了,但仍有发生。
-
test-on-borrow:业务线程获取连接时,无条件每次校验,性能损耗高;
-
test-while-idle:业务线程获取连接时,有条件校验(空闲超阈值才校验),并非后台线程执行;
-
keep-alive:专属后台线程主动巡检探活,不依赖业务请求,提前清理僵死连接;
-
time-between-eviction-runs-millis:后台巡检线程的执行周期,决定所有后台回收、保活任务的执行频率。
-
keep-alive-between-time-millis:连接空闲多久,需要主动保活探活。
-
min-evictable-idle-time-millis:连接空闲多久,允许被彻底回收销毁。
只开前两个,永远无法彻底解决线上僵死连接导致的超时问题,必须搭配keep-alive才能闭环。
二、保活与回收核心参数
1. time-between-eviction-runs-millis 后台巡检周期
默认值:60000ms(60秒)
核心定义:Druid后台销毁线程(DestroyConnectionThread)的执行间隔时间。线程休眠该时长后,执行一次shrink巡检任务。
每次巡检只做两件事:
-
回收空闲超期的无效连接;
-
若开启keep-alive,主动对空闲连接做探活,清理僵死连接。
坑点:
-
它是调度周期,不是连接回收阈值;
-
所有后台保活、回收任务的执行频率,最终由它决定,哪怕保活间隔设为30秒,巡检60秒一次,最多60秒才能完成一次探活;
-
设置过小(<30秒)会频繁扫描连接、执行探活SQL,增加数据库压力;过大(>2分钟)会导致僵死连接长期滞留池中。
生产建议:保持60000ms,均衡稳定性与性能。
2. min-evictable-idle-time-millis 连接最小空闲回收时间
默认值:1800000ms(30分钟)
作用:连接空闲时长超过该值,就会被后台线程判定为可回收连接,执行销毁。
坑点:该值必须小于数据库wait_timeout!MySQL默认8小时,云数据库/防火墙常设置30分钟,若该值大于数据库超时,连接早已被外部断开,池中残留大量僵死连接。
生产建议:300000ms(5分钟),提前回收闲置连接,规避断连问题。
3. test-while-idle 空闲条件校验(业务线程执行)
默认值:false
真实执行逻辑(源码级):
仅当test-on-borrow=false时生效,跑在业务请求线程中,并非后台线程!
触发条件:连接空闲时长 大于等于 time-between-eviction-runs-millis,业务获取连接时才执行SELECT 1校验。
生产建议:true,作为兜底校验,低损耗、高兜底。
4. test-on-borrow 借出无条件校验
默认值:false
作用:每次业务获取连接,无条件执行探活校验。
坑点:高并发场景下频繁执行校验SQL,性能损耗极大,严重影响接口RT。
生产建议:false,绝对不开启,无需冗余校验。
5. keep-alive 后台主动保活
默认值:false
核心作用:开启后,后台巡检线程会主动、提前探活空闲连接,不依赖任何业务请求。
执行流程:
后台每次巡检,遍历所有空闲连接,对空闲时长达到keep-alive-between-time-millis的连接执行探活,坏连接直接销毁,并自动新建连接补齐min-idle数量。
解决的核心问题:彻底解决test-while-idle的滞后性问题,提前清理池中僵死连接,避免业务拿到坏连接、瞬时大量新建连接导致的获取连接超时。
配套参数 keep-alive-between-time-millis:默认120000ms,生产建议60000ms,高频保活,适配云数据库、防火墙环境。
生产建议:keep-alive=true,所有线上环境打开。
三、核心参数速查表
整理Druid线上所有高频核心参数,包含容量、超时、保活、回收、统一汇总个速查表。日常生产配置、故障排查、参数复盘直接对照即可。
| 参数名称 | 默认值 | 作用 | 解决什么问题 | 坑点 | 生产推荐配置 |
|---|---|---|---|---|---|
| initial-size | 0 | 服务启动预先创建的数据库连接数 | 解决冷启动、流量突增时批量建连导致的接口抖动 | 为0会出现上线瞬时卡顿;过大占用过多数据库初始连接 | 8 |
| min-idle | 0 | 连接池最小空闲连接保有量,不足自动补齐 | 避免低峰期连接全部销毁,流量回暖频繁建连 | 远小于max-active会导致连接频繁伸缩,P99抖动严重 | 8 |
| max-active | 8 | 单实例最大数据库连接占用上限 | 防止单服务打满数据库连接,保护整体数据库集群 | 默认8并发不够用;盲目调大会打爆MySQL最大连接数 | 20-30(普通CRUD)30-50(高并发) |
| max-wait | -1 | 连接池打满后,请求排队获取连接超时时间 | 避免线程无限阻塞、堆积,防止服务雪崩假死 | 默认无限等待,线上线程打满、接口全挂、极难排查 | 3000ms |
| max-create-connection-millis | -1 | 单次新建物理连接的最大耗时限制 | 解决连接池没满但依然获取连接超时的诡异问题 | 默认不限制,网络抖动时,建连卡死、线程长时间挂住 | 3000ms |
| not-full-timeout-millis | 0 | 连接池未满、无空闲连接,等待新建连接的超时 | 补齐max-wait盲区,全覆盖所有获取连接超时场景 | 默认无限等待,池子没满也会出现线程卡死、请求超时 | 3000ms |
| time-between-eviction-runs-millis | 60000ms | 后台巡检回收的执行周期 | 定时回收过期空闲连接、触发keep-alive保活探活 | 不是回收阈值;设置过小压库、过大堆积僵死连接 | 60000ms |
| min-evictable-idle-time-millis | 1800000ms | 连接空闲超此时长,允许被后台回收销毁 | 主动回收长期闲置连接,避免僵死连接滞留 | 大于数据库wait_timeout,会出现大量已断连僵尸连接 | 300000ms |
| test-on-borrow | false | 每次获取连接,无条件执行探活校验 | 极致保证每次拿到有效连接 | 高并发下频繁执行SELECT 1,性能损耗大、RT飙升 | false |
| test-while-idle | false | 业务拿连接时,空闲超阈值则条件式探活 | 低性能损耗兜底校验,拦截大部分无效连接 | 后台不执行!仅业务线程触发,短时间断连存在校验盲区 | true |
| keep-alive | false | 开启后台线程主动空闲连接保活巡检 | 彻底解决test-while-idle盲区,提前清理僵死连接 | 不开启仅靠业务触发校验,必然有偶发断连、瞬时建连超时 | true |
| keep-alive-between-time-millis | 120000ms | 空闲连接达到该时长,触发后台保活探活 | 高频巡检,适配云数据库、防火墙自动掐断空闲连接场景 | 数值过大保活滞后,依然残留僵尸连接 | 60000ms |
| remove-abandoned | false | 开启连接泄露强制回收、堆栈打印 | 快速定位代码连接泄露、长事务占连接问题 | 生产长期开启会误杀长事务,导致业务报错、数据异常 | 排查临时开启,常态关闭 |
四、生产配置
type: com.alibaba.druid.pool.DruidDataSource
druid:
# 基础容量配置
initial-size: 8
min-idle: 8
max-active: 30
max-wait: 3000
max-create-connection-millis: 3000
# 后台巡检与回收配置
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
# 连接校验保活配置(核心避坑组合)
validation-query: SELECT 1
test-on-borrow: false
test-on-return: false
test-while-idle: true
keep-alive: true
keep-alive-between-time-millis: 60000