MySQL 连接池配置及 FullGC 分析

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 本文主要讲述MySQL连接池配置不合适时,由于MySQL以虚引用的方式作为线程清理的后备手段,导致JVM年老代随时间缓慢增长,直至FullGC的问题。为了优化数据库连接池配置,使得JVM进行尽量少的FullGC导致服务故障,本文提供了多种解决方案单独的MySQL清理,负责关闭被遗弃的MySQL连接,即没有被显式关闭的连接。发现容器服务的老年代在不断的增长,直到。

本文主要讲述MySQL连接池配置不合适时,由于MySQL以虚引用的方式作为线程清理的后备手段,导致JVM年老代随时间缓慢增长,直至FullGC的问题。为了优化数据库连接池配置,使得JVM进行尽量少的FullGC导致服务故障,本文提供了多种解决方案

问题描述

发现容器服务的老年代在不断的增长,直到FullGC回收

年老代使用比例

MAT dump分析

使用Java自带的jmapjstack,Java 8 引入的jcmd,或Arthas heapdump 等工具,来进行Thread dump

使用MAT进行堆栈日志分析

dump-overview

Leak Suspect

leak-suspect

mysql-connector-java-5.1.49com.mysql.jdbc.AbandonedConnectionCleanupThread单独的MySQL清理,负责关闭被遗弃的MySQL连接,即没有被显式关闭的连接

AbandonedConnectionCleanupThread

ConcurrentHashMap类型的connectionFinalizerPhantomRefs常量,包含了一系列的虚引用。目的是作为保底操作:当connection对象回收时,顺便回收相关资源

如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收器回收的活动。

四种引用类型可见Java 垃圾收集器与内存分配策略

trackConnection

当创建新的连接的时候就会调用trackConnection方法,把MysqlConnection添加到虚引用的ConcurrentHashMap中

由此可以分析出造成年老代不断增长的原因是MySQL连接短时间内不断创建回收的

weak refs processing处理逻辑

此段原文自 https://www.jianshu.com/p/2db280229343

void ReferenceProcessor::process_discovered_references(
  BoolObjectClosure*           is_alive,
  OopClosure*                  keep_alive,
  VoidClosure*                 complete_gc,
  AbstractRefProcTaskExecutor* task_executor) {
   
   
  NOT_PRODUCT(verify_ok_to_handle_reflists());

  assert(!enqueuing_is_done(), "If here enqueuing should not be complete");
  // Stop treating discovered references specially.
  disable_discovery();

  bool trace_time = PrintGCDetails && PrintReferenceGC;
  // Soft references
  {
   
   
    TraceTime tt("SoftReference", trace_time, false, gclog_or_tty);
    process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
                               is_alive, keep_alive, complete_gc, task_executor);
  }

  update_soft_ref_master_clock();

  // Weak references
  {
   
   
    TraceTime tt("WeakReference", trace_time, false, gclog_or_tty);
    process_discovered_reflist(_discoveredWeakRefs, NULL, true,
                               is_alive, keep_alive, complete_gc, task_executor);
  }

  // Final references
  {
   
   
    TraceTime tt("FinalReference", trace_time, false, gclog_or_tty);
    process_discovered_reflist(_discoveredFinalRefs, NULL, false,
                               is_alive, keep_alive, complete_gc, task_executor);
  }

  // Phantom references
  {
   
   
    TraceTime tt("PhantomReference", trace_time, false, gclog_or_tty);
    process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
                               is_alive, keep_alive, complete_gc, task_executor);
  }

  // Weak global JNI references. It would make more sense (semantically) to
  // traverse these simultaneously with the regular weak references above, but
  // that is not how the JDK1.2 specification is. See #4126360. Native code can
  // thus use JNI weak references to circumvent the phantom references and
  // resurrect a "post-mortem" object.
  {
   
   
    TraceTime tt("JNI Weak Reference", trace_time, false, gclog_or_tty);
    if (task_executor != NULL) {
   
   
      task_executor->set_single_threaded_mode();
    }
    process_phaseJNI(is_alive, keep_alive, complete_gc);
  }
}

看JVM源码,weak refs processing主要包括SoftReferenceWeakReferenceFinalReferencePhantomReference以及JNI Weak Reference这五种Reference对象的处理,处理的主要内容是对之前标记的Reference对象重新处理,重新判断是否需要标记(不标记就是要回收的),如果不标记就需要放到refqueue里,等待java ReferenceHandler线程处理

优化方法

调整数据库连接池配置

如果应用程序使用Hikari或任何其他连接池管理器且并在正确的配置下,这些引用将在MinorGC时被回收,不会造成问题

  1. 适当延长idleTimeout(默认值为10分钟,问题进程设置为30s)
  2. 适当延长maxLifetime(数据库默认的连接空闲时间是8小时,问题进程设置为25min)
  3. 调整空闲线程数minimumIdle(默认会和最大连接数一样为100)

Hikari官方强烈推荐设置maxLifetime,并只比数据库引擎connectionTimeout短一些

spring:
  datasource:
    test:
      # 一个连接idle状态的最大时长(毫秒),超时则被释放(retired),默认:10分钟
      idle-timeout: 1800000
      # 一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms,建议设置比数据库超时时长少60秒,参考MySQL wait_timeout参数(show variables like '%timeout%';) -->  ) -->
      max-lifetime: 14400000
      # 连接池中允许的最大连接数。缺省值:10;推荐的公式:((core_count * 2) + effective_spindle_count)
      maximum-pool-size: 100
      # 最小连接数
      minimum-idle: 10

设置JVM参数

在Java参数中设置了-Dcom.mysql.cj.disableAbandonedConnectionCleanup=true,停止生成这些引用

删除connectionFinalizerPhantomRefs集合

数据库连接的释放有连接池保证,这个保底机制其实是多余的,可以起个定时任务线程,去清理这个connectionFinalizerPhantomRefs集合。

下面是一个旧版本的清理示例代码。
在这里插入图片描述


参考资料:

  1. MySQL AbandonedConnectionCleanupThread Memory Leak
  2. 记一次数据库连接池导致的OOM的问题
  3. 数据库连接池配置不当导致的full gc问题记录
  4. HikariCP
相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
9天前
|
存储 监控 关系型数据库
rds迁移前准备资源评估与配置
rds迁移前准备资源评估与配置
21 5
|
25天前
|
关系型数据库 MySQL Serverless
高顿教育:大数据抽数分析业务引入polardb mysql serverless
高顿教育通过使用polardb serverless形态进行数据汇总,然后统一进行数据同步到数仓,业务有明显高低峰期,灵活的弹性伸缩能力,大大降低了客户使用成本。
|
1月前
|
关系型数据库 MySQL 索引
【MySQL 解析】Hash索引和B+树索引对比分析
【1月更文挑战第11天】【MySQL 解析】Hash索引和B+树索引对比分析
|
1月前
|
SQL 关系型数据库 MySQL
Mycat【Mycat部署安装(核心配置及目录结构、安装以及管理命令详解)Mycat高级特性(读写分离概述、搭建读写分离、MySQL双主双从原理)】(三)-全面详解(学习总结---从入门到深化)
Mycat【Mycat部署安装(核心配置及目录结构、安装以及管理命令详解)Mycat高级特性(读写分离概述、搭建读写分离、MySQL双主双从原理)】(三)-全面详解(学习总结---从入门到深化)
35 0
|
13天前
|
存储 运维 关系型数据库
规划阿里云RDS跨区迁移业务需求业务影响分析
规划阿里云RDS跨区迁移业务需求业务影响分析
12 4
|
16天前
|
监控 关系型数据库 MySQL
MySQL技能完整学习列表12、性能优化——1、性能指标和监控——2、优化查询和数据库结构——3、硬件和配置优化
MySQL技能完整学习列表12、性能优化——1、性能指标和监控——2、优化查询和数据库结构——3、硬件和配置优化
57 0
|
22天前
|
SQL 存储 关系型数据库
MySQL(终结篇二)- SQL 语句分析与优化
MySQL(终结篇二)- SQL 语句分析与优化
74 0
|
22天前
|
SQL 缓存 关系型数据库
MySQL(终结篇一)- 性能优化(配置及架构)
MySQL(终结篇一)- 性能优化(配置及架构)
89 0
|
1月前
|
关系型数据库 MySQL 数据库
MySQL的启动停止,与环境变量配置
MySQL的启动停止,与环境变量配置
|
1月前
|
关系型数据库 MySQL 数据库
MySQL安装配置初始化 Windows10安装8.0.23版本
MySQL是应用最广泛、普及度最高的开源关系型数据库。
26 0

热门文章

最新文章