news 2026/10/29 19:47:37

Druid连接池:8个最常配错的参数、默认值与生产推荐值

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Druid连接池:8个最常配错的参数、默认值与生产推荐值

Druid连接池:8个最常配错的参数、默认值与生产推荐值

【免费下载链接】druid阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池项目地址: https://gitcode.com/gh_mirrors/druid/druid

凌晨 3 点,应用集体抛出 GetConnectionTimeoutException,重启才恢复——这类故障十有八九是 Druid 连接池参数没配到位:连接被占满、死连接混进业务、泄漏无人发现。Druid 是阿里云 DataWorks 团队出品的数据库连接池,它的参数默认值大多偏向"安全"而非"高性能",照默认值裸奔能跑,但撑不过高峰。这篇文章按故障场景把最该动的参数一次讲清,并给出可直接拷贝的配置。

本文你能带走四样东西:

  • 拿到一份带默认值、生产推荐值、改错后果的参数速查表
  • 按"连接耗尽 / 死连接 / 泄漏"三大故障理解参数,出问题时知道动哪个
  • 拷走 3 份按场景写好的完整配置(首次上线、核心交易、多副本)
  • 学会用监控页和日志读数验证"改对了没有"

上节监控页就是本文后面所有"验证手段"的入口:配置改完,先看这里。

参数速查总表:默认值与生产推荐值

所有默认值取自 DruidAbstractDataSource.java,推荐值按常见单库、20 线程级并发的场景给出,具体数字后面每节都会解释。

参数默认值生产推荐值改错的后果
maxActive820~50并发一上来就排队,数据库 max_connections 才是真上限
maxWait-13000~5000ms-1 是无限等待,连接池一耗尽全部业务线程卡死
minIdle0maxActive 的 1/4~1/2低谷期没有热连接,流量突增时现场建连接,RT 毛刺
testWhileIdletruetrue关掉后死连接要等下次检测才暴露
timeBetweenEvictionRunsMillis6000060000调太小浪费,调太大死连接窗口变长
minEvictableIdleTimeMillis1800000≥ 数据库 wait_timeout小于它,空闲连接刚建好就被清掉
phyTimeoutMillis-13600000(1h)-1 永不主动销毁,死连接只能被动发现
removeAbandonedfalse生产 false(定位期短暂开 true)强开会误杀长事务,源码注释明确不建议生产使用

连接为什么会被耗尽:maxActive 与 maxWait

应用报 GetConnectionTimeoutException,本质是"要连接的人"多于"池里的连接"。三个参数决定这个平衡:maxActive 定并发上限,maxWait 定等不到时线程的行为,minIdle 定冷启动表现。异常本身定义在 GetConnectionTimeoutException.java。

参数默认值生产推荐值一句话原因
initialSize05启动时预热几个连接,避开第一波流量的建连开销
maxActive820~50默认 8 太小;超过 50 时先怀疑慢 SQL 或泄漏,别无脑加
minIdle0maxActive 的 1/4~1/2保持热连接,低谷不浪费、高峰不建连
maxWait-13000~5000ms设成保险丝:池耗尽时快速失败,而不是线程无限排队
maxWaitThreadCount-130~100限制排队线程数,防止数据库故障时线程堆积打满 JVM
# ===== 连接容量 ===== spring.datasource.druid.initial-size=5 # 启动预热连接数 spring.datasource.druid.max-active=20 # 并发上限,按业务线程数估算 spring.datasource.druid.min-idle=8 # 低谷期保留的热连接 spring.datasource.druid.max-wait=5000 # 拿不到连接 5 秒即抛异常,快速失败 spring.datasource.druid.max-wait-thread-count=50 # 排队线程封顶,防线程堆积

注意:minIdle 不能大于 maxActive,否则 setMinIdle 会直接抛 IllegalArgumentException。

这节解决的是:连接池在高峰时"接不住"或"排队卡死"。

死连接怎么混进业务:testWhileIdle 组合

数据库重启、网络切换、超过 MySQL 的 wait_timeout,池里的物理连接就死了。验证机制没配对时,这些死连接会被借给业务线程,抛出五花八门的"通讯链路断裂"异常。

参数默认值生产推荐值一句话原因
validationQuerynullSELECT 1各库通用的最小验证 SQL(Oracle 用 SELECT 1 FROM DUAL)
testOnBorrowfalsefalse每次借出都验证一次,高并发下 RT 明显上升
testOnReturnfalsefalse归还时验证同样浪费,靠空闲检测兜底即可
testWhileIdletruetrue默认就是 true,别关:空闲检测是唯一常态化剔除死连接的手段
timeBetweenEvictionRunsMillis600006000060 秒一轮,兼顾开销与死连接暴露窗口
# ===== 连接有效性 ===== spring.datasource.druid.validation-query=SELECT 1 # 验证 SQL spring.datasource.druid.test-while-idle=true # 空闲时检测,剔除死连接 spring.datasource.druid.time-between-eviction-runs-millis=60000 # 检测间隔 60s spring.datasource.druid.min-evictable-idle-time-millis=3600000 # 空闲 1h 才允许清

注意:minEvictableIdleTimeMillis 必须大于数据库侧的 wait_timeout(MySQL 默认 8 小时),否则连接被数据库断掉前池子自己就清了,清得越多重建越频繁。

这节解决的是:偶发"连接已关闭/通讯链路失效"类异常。

连接泄漏怎么被定位:removeAbandoned 的正确用法

泄漏的典型读数是 activeCount 只增不减,minIdle 兜不住、maxWait 被反复触发。Druid 的 removeAbandoned 会在连接借出超时后强制回收并打堆栈,但它在源码里的警告很直接:

# ===== 泄漏定位 ===== spring.datasource.druid.log-abandoned=true # 回收时打印借出堆栈,定位泄漏代码 spring.datasource.druid.remove-abandoned=false # 生产保持 false
参数默认值生产推荐值一句话原因
logAbandonedfalsetrue只记堆栈不误杀,是定位泄漏的关键开关
removeAbandonedfalse生产 false,排障期短暂 true强回收会杀掉运行超过阈值的正常长事务
removeAbandonedTimeoutMillis300000按业务最长事务上浮 50%阈值低于最长事务时长就是误杀

注意:DruidDataSource 中 setRemoveAbandoned(true) 会打 warn 日志"removeAbandoned is true, not use in production"——把它当排障开关用,不当常态防护用。

定位手法:短暂开 removeAbandoned + logAbandoned,看日志里的借出堆栈找到漏关连接的代码;或者在监控页"Web应用"页对照 URI 的 JDBC 执行次数与活跃连接。修完代码后记得关回去。

这节解决的是:连接池被慢慢"吃光"却查不到源头。

物理连接该活多久:phyTimeoutMillis

phyTimeoutMillis 默认 -1,物理连接永不主动销毁;phyMaxUseCount 默认 -1,一个连接执行 SQL 没有次数上限。两者都意味着死连接和脏状态只能被动发现。

# ===== 物理连接生命周期 ===== spring.datasource.druid.phy-timeout-millis=3600000 # 1 小时主动换血 spring.datasource.druid.phy-max-use-count=100000 # 执行 10 万次后强制重建
参数默认值生产推荐值一句话原因
phyTimeoutMillis-13600000(1h)主动换血比等死连接被检测出来成本低
phyMaxUseCount-1100000给连接"服役时长"上限,防状态积累

这节解决的是:运行数天后才出现的偶发连接失效。

PreparedStatement 缓存到底开不开

池化让固定模板 SQL 复用服务端编译结果。CRUD 模板 SQL 多、重复执行的高并发场景收益明显;动态拼接 SQL 多的场景收益低还占内存。实现见 PreparedStatementPool.java。

参数默认值生产推荐值一句话原因
poolPreparedStatementsfalse模板 SQL 多则 true开启前先看 SQL 监控页确认 SQL 集中度
maxPoolPreparedStatementPerConnectionSize1050每连接缓存条数,按业务 SQL 模板数定
sharePreparedStatementsfalse保持 false跨连接共享引入额外复杂度,收益有限
# ===== PS 缓存(确认 SQL 模板集中后再开)===== spring.datasource.druid.pool-prepared-statements=true spring.datasource.druid.max-pool-prepared-statement-per-connection-size=50

注意:先开 stat 过滤看 SQL 模板集中度再决定开不开,别凭感觉开——模板 SQL 不集中时纯占内存。

这节解决的是:固定 SQL 高并发下 prepare 开销占比高的问题。

场景配方:三份可直接拷贝的配置

配方一:首次上线最小可用版

spring.datasource.druid.initial-size=5 spring.datasource.druid.max-active=20 spring.datasource.druid.min-idle=5 spring.datasource.druid.max-wait=3000 # 快速失败,上线初期宁可报错也别卡线程 spring.datasource.druid.validation-query=SELECT 1 spring.datasource.druid.test-while-idle=true spring.datasource.druid.time-between-eviction-runs-millis=60000 spring.datasource.druid.log-abandoned=true # 上线初期多留一双眼睛

为什么这么配:容量保守、失败快速、只开无副作用的防护。maxWait 设 3000ms 是为了让泄漏和慢 SQL 在第一周就暴露成异常,而不是被无限等待掩盖。

配方二:核心交易接口加固版

在配方一基础上追加:

spring.datasource.druid.max-wait=5000 spring.datasource.druid.max-wait-thread-count=50 spring.datasource.druid.phy-timeout-millis=3600000 spring.datasource.druid.min-evictable-idle-time-millis=3600000 spring.datasource.druid.connection-properties=druid.stat.slowSqlMillis=500 # 记录 >500ms 的 SQL

为什么这么配:交易接口对毛刺敏感,物理连接 1 小时换血避免"服役过久"的连接;slowSqlMillis 设 500ms 让占用连接过长的 SQL 可追溯。

配方三:多副本生产版(8 副本 × 20 连接)

spring.datasource.druid.max-active=20 # 8 副本 × 20 = 160,需 < 数据库 max_connections spring.datasource.druid.async-init=true # 异步建连,缩短发布窗口 spring.datasource.druid.break-after-acquire-failure=true # 建连失败不再反复重试 spring.datasource.druid.connection-error-retry-attempts=1 # 重试 1 次即快速失败 spring.datasource.druid.min-idle=8

为什么这么配:多副本下真正的上限是数据库侧连接数,先算总量再定单副本容量;asyncInit 让滚动发布少等几十秒;breakAfterAcquireFailure 防止数据库故障时每个副本都在后台反复建连,把故障放大成雪崩。

自诊断表:现象 → 原因 → 该动什么

现象可能原因该动的参数 / 动作
GetConnectionTimeoutException 频发连接耗尽或 maxWait 太短先查 activeCount 是否贴 maxActive;是则优化慢 SQL,再考虑加 maxActive
高峰 RT 毛刺、偶发建连延迟minIdle 为 0,现场建连接minIdle 提到 maxActive 的 1/4
偶发"连接已关闭/通讯链路断裂"死连接借出确认 testWhileIdle=true;调 minEvictableIdleTimeMillis > wait_timeout
activeCount 缓慢增长不回落连接泄漏开 logAbandoned + 短暂开 removeAbandoned 抓堆栈
数据库故障后恢复慢、日志刷建连错误默认不断重试建连breakAfterAcquireFailure=true,调小 connectionErrorRetryAttempts
内存随运行时间上涨PS 缓存过开调小 maxPoolPreparedStatementPerConnectionSize 或关闭池化
应用启动慢initialSize 大 + 同步初始化开 asyncInit=true

验证:怎么判断改对了

改完配置,用三个手段读数(对应监控页入口见文首截图):

  1. 监控页"数据源"页:看 ActiveCount 和 WaitThreadCount。正常读数:ActiveCount 明显低于 maxActive 且平稳,WaitThreadCount 长期为 0、只在流量尖刺时短暂出现个位数。
  2. 日志:观察create connection、discard connection、remove abandoned connection关键词。正常读数:稳态下几乎没有 discard(频繁 discard 说明验证配置和 wait_timeout 打架);排障期能看到 remove abandoned 后跟借出堆栈。
  3. JSON API:监控页右上角"查看 JSON API",拉取activeCount、recycleCount、errorCount与改配前对比。正常读数:errorCount 不随时间上涨,recycleCount 缓慢增长。

Druid 连接池的调优核心就三件事:把连接供给(容量与等待)算清楚,把死连接清理(检测与换血)配成闭环,把泄漏定位(堆栈日志)留在手边。每个参数都有默认值可查、推荐值可抄、监控读数可验证。下一步值得深入的是 SQL 监控与慢查询分析——找到真正占住连接过长的 SQL,比调任何参数都有效。你有哪类故障场景还没覆盖到?留言说说,下一期挑一个最常见的接着拆。

【免费下载链接】druid阿里云计算平台DataWorks(https://help.aliyun.com/document_detail/137663.html) 团队出品,为监控而生的数据库连接池项目地址: https://gitcode.com/gh_mirrors/druid/druid

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 19:25:32

GoFrame+Vue3+ElementPlus 动态表格列配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/29 19:25:31

GoFrame+Vue3+ElementPlus 后台开发流程拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/29 19:23:44

基于GD32HC与minimp3的软解码MP3播放器设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/29 19:22:20

网站整站下载器实战:wget镜像与Playwright动态补抓全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/29 19:20:47

HTML菜单源码拆解:从下拉菜单到响应式导航的完整实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华