当前位置: 首页 > news >正文

数据库连接池性能优化实战

 背景

我们公司正在处于某个项目的维护阶段,领导对资源告警比较重视,服务器资源告警的就不说了,运维同学每隔一小时都会检测线上环境的应用服务信息,例如:网关日志响应时间告警/nginx日志接口响应时间告警/日志关键字异常日志告警等,每周都需要对告警信息的排查分析~

都是通过邮件发送给干系人~

 例如,这个是邮件信息截图~

 排查思路

日志--【检索】->traceId--【skywaling】->完整的调用链信息

1.从日志中查到TraceId。

2.通过TraceId获取调用链

通过traceId在skywalking中的可视化界面上可以看出获取数据库链接就花费了7百多毫秒

大家无需纠结接口花费了6s多,而本次却在重点说获取链接池的情况。其他的可以从代码或者sql进行入手优化~~只是获取数据库链接耗时较多,所以着重进行了分析。

3.查看该应用的数据库链接池配置

    druid:# 初始化时建立物理连接的个数initial-size: 20# 最大连接池数量max-active: 100# 最小连接池数量min-idle: 20# 获取连接时最大等待时间max-wait: 60000# 是否缓存preparedStatement,也就是PSCache。pool-prepared-statements: false# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。max-pool-prepared-statement-per-connection-size: -1# 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。validation-query: SELECT 'x'# 单位:秒,检测连接是否有效的超时时间。validation-query-timeout: 1# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。test-on-borrow: false# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。test-on-return: false# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。test-while-idle: true# 有两个含义:1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明time-between-eviction-runs-millis: 6000# 连接保持空闲而不被驱逐的最小时间min-evictable-idle-time-millis: 1200000max-evictable-idle-time-millis: 1800000# 监控页面相关配置stat-view-servlet:url-pattern: /druid/*allow: ""enabled: true

4.获取该应用数据库链接池的监控(需要对应的时间段)

从图中可以看出PoolingCount在这个时刻突然下降,突然下降可能表示有突发流量

详细解释(poolingCount )

在数据库连接池监控中,poolingCount 是一个重要的监控指标,它表示当前连接池中空闲的、可用的数据库连接数量

含义

  • poolingCount 表示连接池中当前处于空闲状态、可以被应用程序直接获取使用的连接数量

  • 这些连接已经创建并与数据库建立了连接,但暂时没有被应用程序使用

  • 它是连接池中"准备好的"连接的数量

相关指标对比

在常见的连接池实现中,通常会有以下相关指标:

指标名称含义
poolingCount当前空闲连接数
activeCount当前活跃连接数(正在被使用的连接)
maxActive连接池最大允许的连接数
minIdle连接池保持的最小空闲连接数
maxIdle连接池允许的最大空闲连接数

监控意义

  1. 性能调优依据

    • 如果 poolingCount 经常为0,可能表明连接池配置过小

    • 如果 poolingCount 长期很高,可能表明配置过大

  2. 问题诊断

    • poolingCount 突然下降可能表示有突发流量

    • poolingCount 长期低位可能表示连接泄漏

  3. 容量规划

    • 结合 activeCount 和 poolingCount 可以评估连接池使用情况

    • 帮助确定合适的 maxActive 和 minIdle 参数

✅ 图表汇总分析(监控时间:近6小时)

1. IdleConnection(空闲连接)

  • 大部分时间维持在 20 左右,直到接近 14:00 时突然拉升。

  • 说明min-idle: 20 已经生效,Druid 正在努力维持至少 20 个空闲连接。


2. PoolingCount(连接池中的连接总数)

  • 长期稳定在 5~10 左右,你说的问题验证了。

  • 但注意这个指标来源标注为 TotalConnection(...),它并非严格意义的“空闲连接数”,可能是连接池当前存在的连接总数(和 Idle + Active 的关系要确认 exporter 定义)。


3. ActiveConnection(活跃连接数)

  • 绝大多数时间活跃连接在 0~2 之间

  • 即使接近 14:00 的高峰期,也只有少量连接(<10)在活跃使用;

  • 说明系统当前数据库并发负载是低的


4. ThreadsAwaitingConnection(等待获取连接的线程数)

  • 全程为 0;

  • ✅ 说明连接池没有连接耗尽问题,应用线程从不需等待连接。


5. MaxConnection(连接池历史最大并发连接数)

  • 常态是 4,只有在快到 14:00 时突增至 200;

  • 猜测是某个服务(或某次压测)在那个时段拉高了连接数。


✅ 结论

项目结论
min-idle 是否生效?✅ 是的,空闲连接维持在 20
是否存在连接不足 / 堵塞?❌ 没有。activeCountwaitThreadCount 都非常低
是否需要增加 min-idle?目前不需要,现有配置已满足需求
是否要扩大连接池?❌ 不需要,max-active: 100 远超实际并发需求

当前链接数在22左右,超过了预热的的链接数20,所以需要与mysql中建立链接。

思考:

但是为什么与mysql建立链接这么长时间?

1.mysql的监控

Threads Cached = 1 意味着什么?

这表示:

  • 当前 MySQL 有 1 个空闲线程 在等待下一个连接复用;

  • 如果有新连接请求到来,MySQL 可以立刻用这 1 个线程处理,而 无需调用 pthread_create() 创建新线程

重点观察图表分析

1. 线程缓存 (MySQL Thread Cache)

  • Threads Created 几乎为 0,说明线程缓存有效;

  • 但 Threads Cached 明显有下降段(21:45 前后出现断崖);

  •  表示短时间内大量连接请求导致缓存线程被用完,需新建线程。

这会造成连接响应变慢,尤其是连接池新建连接时要与数据库创建新线程,代价高。


2. 临时表 (MySQL Temporary Objects)

  • 每秒创建临时表数在 4~5 个,且偶尔触发 Created Tmp Disk Tables(磁盘临时表);

  • 说明存在大量使用 GROUP BYORDER BY、子查询、联合查询等临时表消耗。

 磁盘临时表严重影响 SQL 响应速度,从而增加连接持有时间。


3. 排序 (MySQL Sorts)

  • Sort Rows 高峰时可达 30~40;

  • Sort Scan 也非 0,说明未命中索引的排序操作存在。

 排序越多、越复杂,单个 SQL 执行越慢 → 应用端连接持有时间越长 → 导致连接池空闲不足。


4. Select Types 分布

  • Select Scan 稳定在高位,说明存在大量全表扫描;

  • Select Range 较低,表示索引未能充分利用。


5. 慢查询 (MySQL Slow Queries)

  • 21:45 左右出现明显慢 SQL 峰值,最高达 1.45/s;

  • 时间点与线程缓存耗尽、临时表升高高度吻合!


综合分析:导致连接获取慢的根因

MySQL 层临时表多 / 排序多 / 索引未命中SQL 响应时间延长,连接被长时间占用
MySQL 层Thread Cache 命中率下降新建线程成本高,拖慢新连接初始化
应用层连接池配置不足 / minIdle 过低无法预热足够连接,应对突发请求
应用层SQL 过慢 + 连接未及时释放导致连接池回收和复用效率变差

 优化建议

A. MySQL 层建议

慢查询排查开启 slow_query_log,排查 21:45 的慢 SQL
索引优化优化 SELECT SCAN 多的表结构,添加合适联合索引
避免临时表检查是否有复杂嵌套子查询 / group by 未配 index
调大线程缓存thread_cache_size = 128
临时表优化调整 tmp_table_size 和 max_heap_table_size 至 128M 起步
排序优化优化 ORDER BY 相关 SQL,能使用索引就用索引

B. 应用层建议(Druid)

spring:datasource:druid:initial-size: 30min-idle: 30max-active: 100max-wait: 30000validation-query: SELECT 1test-on-borrow: truetest-while-idle: truetime-between-eviction-runs-millis: 5000remove-abandoned: trueremove-abandoned-timeout: 180log-abandoned: true

重点说明:

  • initial-sizemin-idle: 提高初始连接和空闲连接数,快速预热;

  • test-on-borrow: 确保连接可用,避免使用“死连接”;

  • remove-abandoned: 回收长时间未关闭连接,防止泄露;

  • max-wait: 缩短应用等待连接时间,提高失败可控性;

总结一句话:

MySQL 当前存在执行慢 / 缓存线程耗尽 / 排序临时表密集的问题,间接导致应用端连接获取慢,连接池设置不当进一步放大了问题

当前mysql数据库设置:

SHOW VARIABLES LIKE 'thread_cache_size';

68 

将thread_cache_size 调整到128后,后续再看结果

http://www.dtcms.com/a/308792.html

相关文章:

  • 【RH134 问答题】第 13 章 运行容器
  • 谷歌浏览器之f12打开控制台debugger模式实现条件控制打印输出及字节数组条件
  • Java 并发编程基础概念与常见问题梳理
  • 电商项目_性能优化_高并发缓存一致性
  • 【Unity笔记04】数据持久化
  • HTM 5 的离线储存的使用和原理
  • Unity游戏开发中的3D数学基础详解
  • MATLAB 2025a的下载以及安装,安装X310的测试附加功能(附加安装包)
  • 因为想开发新项目了~~要给老Python项目整个虚拟环境
  • 旋转花键在机械加工中心ATC装置中有什么优势?
  • 01 全基因组关联分析原理
  • vlan技术
  • 【PHP属性详解:从基础到只读的完全指南】
  • 企业智脑1.3.1技术升级全面解读:AI笔记引擎如何重塑企业知识管理范式
  • 计算机系统基础与操作系统笔记
  • Spring Boot Admin 监控模块笔记-实现全链路追踪
  • 另外几种语言挑战100万行字符串文本排序
  • Web开发-PHP应用原生语法全局变量数据接受身份验证变量覆盖任意上传(代码审计案例)
  • 风力发电场景下设备状态监测与智能润滑预测性维护策略
  • 【Python气象可视化】用Cartopy+Matplotlib绘制青藏高原涡移动轨迹图(附完整代码+颜色渐变时间轴)
  • 数据库学习--------数据库日志类型及其与事务特性的关系
  • 题目:BUUCTF之rip(pwn)
  • [算法]Leetcode3487
  • 【高等数学】第七章 微分方程——第五节 可降阶的高阶微分方程
  • 第三章·数据链路层
  • 前端路由深度解析:Hash 模式 vs. History 模式
  • 数字化应急预案:构筑现代安全防线
  • 实时语音流分段识别技术解析:基于WebRTC VAD的智能分割策略
  • MySQL 中的事务隔离级别有哪些?分别解决什么问题?
  • 图结构知识构造方法详解 ——面向垂直领域的高效知识库构建方案