Su的技术博客

  • 首页
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • AI
  • Other
  • 工具
  • 打赏
  • 关于
路很长,又很短
  1. 首页
  2. 事故复盘
  3. 正文
                           

【京东零售】线上问题处理案例1:出乎意料的数据库连接池

2023-02-16 359点热度 0人点赞 0条评论
简介


本文是《线上问题处理案例》系列之一,该系列旨在通过真实案例向读者介绍发现问题、定位问题、解决问题的方法。本文讲述了从垃圾回收耗时过长的表象,逐步定位到数据库连接池保活问题的全过程,并对其中用到的一些知识点进行了总结。



一、问题描述




大促期间,某接口超时次数增多,FullGC达500ms以上。




二、应用基本情况




  • 容器:8C12G;

  • JVM配置:-XX:+UseConcMarkSweepGC -Xms6144m -Xmx6144m -Xmn2048m -XX:ParallelGCThreads=8 -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+ParallelRefProcEnabled;

  • 数据库类型:MySQL;

  • 数据库连接池:DBCP;



三、排查过程




1、GC耗时过长,说明内存中垃圾对象很多。

2、首先怀疑是否有内存泄漏,观察FullGC后堆内存回收情况,尚属正常,暂时排除内存泄漏原因。



3、推断FullGC耗时过长是否因为老年代有大量死亡对象,遂导出FullGC前后堆内存dump,通过比对“保留大小”,发现FullGC后大量数据库相关对象被回收。



4、数据库连接正常应该不会频繁创建和断开,进入老年代后,正常不应该被回收,通过堆dump内容OQL分析每个数据库连接数量,发现很多库连接数都大于“maxActive”数量,可以肯定有很多失效连接。

5、初步判断直接原因是很多失效数据库连接进入老年代,导致FullGC耗时过长。

6、怀疑连接池验证周期过长,导致数据库因空闲过长关闭连接,将连接池参数“timeBetweenEvictionRunsMillis”由1分钟调整到10秒,问题依旧。

7、阅读DBCP源码,发现是通过org.apache.commons.pool.impl.GenericObjectPool.Evictor定时任务,按照timeBetweenEvictionRunsMillis配置的周期定时驱逐失效连接,驱逐条件:若连接空闲时间大于“minEvictableIdleTimeMillis”,则会驱逐连接,等待垃圾回收。若开启“testWhileIdle”则会执行“validationQuery”。进一步阅读代码,发现执行“validationQuery”后,连接空闲时间并不会重新计算,导致连接在业务低谷时很容易被淘汰,而数据库连接会关联大量对象,创建、回收成本昂贵,并且影响GC。

8、反向思考,为何只有在大促期间才发生问题?


可以看到平时由于业务量小,GC不频繁,过期连接没有达到进入老年代阈值,在年轻代被回收。而大促时业务量大,GC频繁,连接在进入老年代以后才过期,导致老年代FullGC时间过长。
9、至此,基本可以肯定问题原因是数据库连接池不具备“保活”能力,导致连接不断淘汰和新建,在业务高峰时段,连接进入老年代然后失效,造成FullGC耗时过长,最终导致接口超时次数增多。



四、解决方案




方案1:改为G1回收器;

方案2:minEvictableIdleTimeMillis设置为0;



五、问题总结




数据库连接池并不具备通常理解的“保活”能力,数据库连接在业务不活跃的应用中,会不断淘汰和重连,而连接会通过虚引用方式(com.mysql.jdbc.NonRegisteringDriver$ConnectionPhantomReference)携带大量对象,如果连接存活时间内YGC次数达到寿命阈值,则会进入老年代,老年代是使用“标记-清除”算法,回收成本更高,进而造成FullGC耗时过长。



六、拓展知识点




1、Druid连接池同样存在不能“保活”问题,较新版本提供“KeepAlive”选项(未验证);

2、Druid连接池配置的“validationQuery”语句通常并不会被执行,MySqlValidConnectionChecker在检查连接有效性时,会判断驱动是否实现pingInternal方法,如果实现则会通过此方法验证有效性。MySQL的JDBC驱动实现了该方法,因此“validationQuery”配置的语句通常不会执行;



3、DBCP和Druid连接池默认都是FILO,如果业务不繁忙,会导致只有最前边的连接被使用-归还-使用,后边连接基本都在无谓的驱逐、重建连接;

4、虚引用对GC的影响:这些引用只有经过两次GC才能被回收掉,如果进入老年代,则必须经过两次FullGC才能释放内存。本例中由于不断有新的虚引用对象在老年代失效,导致FullGC后,内存水位仍然偏高,会加剧GC压力。新版本JVM已对此做了优化,一次GC可以回收掉;

5、类似的影响还有finalize方法;

6、CMS回收器默认MaxTenuringThreshold为6,而ParallelGC和G1均默认15;

来源: 京东零售技术

更多文章:

  1. mysql-connect-java驱动从5.x升级到8.x的CST时区问题
  2. 记一次升级MySQL驱动包引发的事故
  3. Spring事务无法生效的11个场景
  4. Go整洁架构实践
  5. 可插拔组件设计机制—SPI
  6. 随机高并发查询结果一致性设计实践
  7. 殷浩详解DDD 第四讲:领域层设计规范
  8. 一次磁盘占用率 100% 的排查记录
标签: 京东零售 GC CMS druid 数据库 线上问题 连接池 垃圾回收
最后更新:2023-02-19

coder

分享干货文章,学习先进经验。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

最新 热点 推荐
最新 热点 推荐
图解Git ChatGLM:ChatGPT的替代方案 关于聚合根、领域事件的那点事——深入浅出理解DDD 系统设计 | UUID 和 自增 ID 怎么选? Vim 一下日志文件,Java 进程没了? DDD系列第五讲:聊聊如何避免写流水账代码 LLM下半场之Agent基础能力概述:Profile、Memory、Plan、Action、Eval学习笔记 浅析Redis大Key
OpenAI震撼技术圈!0代码构建Assistants API,技术原理探秘LLM下半场之Agent基础能力概述:Profile、Memory、Plan、Action、Eval学习笔记系统设计 | 导入和导出系统设计 | 如何管理应用系统中的配置?系统设计 | UUID 和 自增 ID 怎么选?Vim 一下日志文件,Java 进程没了?关于聚合根、领域事件的那点事——深入浅出理解DDD浅析Redis大Key
系统设计 | UUID 和 自增 ID 怎么选? 订单超时怎么处理?我们用这种方案 系统设计 | 如何管理应用系统中的配置? 分布式事务的几种实现方式 京东平台研发朱志国:领域驱动设计(DDD)理论启示 图解Git 百度工程师浅谈分布式日志 45 个 Git 经典操作场景,专治不会合代码

618 (1) Agent (2) AIGC (1) bigkey (2) chatglm (1) checkout (1) commit (2) Disruptor (1) Excel (1) FGC (3) G1 (1) G1GC (2) git (2) GLM (1) hotkey (1) LangChain (1) LLM (3) mvc (1) OpenAI (2) ParNew (3) pull (1) push (1) solid (1) UUID (1) Vim (1) vivo (2) ygc (1) 业务编号 (1) 事务隔离级别 (1) 低耦合 (1) 依赖注入原则 (1) 分布式ID (1) 分支 (1) 分页 (3) 单一职责原则 (1) 命名 (1) 垃圾回收器 (7) 大模型 (2) 大语言模型 (1) 开源 (1) 开闭原则 (1) 微博 (1) 微服务 (1) 性能调优 (10) 接口隔离原则 (1) 数据字典 (1) 数据导入 (1) 数据导出 (1) 方案设计 (7) 权限 (1) 架构师 (1) 架构模式 (1) 架构设计 (4) 架构风格 (1) 模块 (1) 死锁 (1) 测试策略 (1) 滴滴 (1) 版本控制 (2) 电商 (2) 系统架构 (4) 编程语言 (2) 订单号 (1) 认证 (1) 软件架构 (2) 配置 (1) 里氏替换原则 (1) 鉴权 (1) 降级 (1) 高内聚 (1)

COPYRIGHT © 2014-2023 verysu.com . ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2