威海做网站的公司有哪些,做承兑 汇票一般会用哪些网站,如何注册网站免费注册,在线购物网站设计导读
本文是线上问题处理案例系列之一#xff0c;旨在通过真实案例向读者介绍发现问题、定位问题、解决问题的方法。本文讲述了从垃圾回收耗时过长的表象#xff0c;逐步定位到数据库连接池保活问题的全过程#xff0c;并对其中用到的一些知识点进行了总结。
一、问题描述…导读
本文是线上问题处理案例系列之一旨在通过真实案例向读者介绍发现问题、定位问题、解决问题的方法。本文讲述了从垃圾回收耗时过长的表象逐步定位到数据库连接池保活问题的全过程并对其中用到的一些知识点进行了总结。
一、问题描述
大促期间某接口超时次数增多经排查直接原因是GC耗时过长查看监控FullGC达500ms以上接口超时时间与FullGC发生时间吻合。 图1 FullGC耗时监控
二、应用基本情况
容器8C12GJVM配置-XX:UseConcMarkSweepGC -Xms6144m -Xmx6144m -Xmn2048m -XX:ParallelGCThreads8 -XX:UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction70 -XX:ParallelRefProcEnabled数据库类型MySQL数据库连接池DBCP
三、排查过程
1、 GC耗时过长说明内存中垃圾对象很多。
2、 首先怀疑是否有内存泄漏观察FullGC后堆内存回收情况尚属正常暂时排除内存泄漏原因。 图2 发生FullGC后堆内存回收监控
3、 推断FullGC耗时过长是否因为老年代有大量死亡对象遂导出FullGC前后堆内存dump通过比对“保留大小”发现FullGC后大量数据库相关对象被回收。 图3 堆内存对象分析
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、 反向思考为何只有在大促期间才发生问题 图4 平时和大促时回收频率对比
可以看到平时由于业务量小GC不频繁过期连接没有达到进入老年代阈值在年轻代被回收。而大促时业务量大GC频繁连接在进入老年代以后才过期导致老年代FullGC时间过长。
9、 至此基本可以肯定问题原因是数据库连接池不具备“保活”能力导致连接不断淘汰和新建在业务高峰时段连接进入老年代然后失效造成FullGC耗时过长最终导致接口超时次数增多。
四、解决方案
方案1改为G1回收器对老年代回收是分块进行可以防止长时间停顿。另外默认MaxTenuringThreshold值是15可以防止失效连接过早进入老年代
方案2 minEvictableIdleTimeMillis设置为0使数据库连接不会自动失效进入老年代以后一直存活避免在老年代失效回收
五、问题总结
数据库连接池并不具备通常理解的“保活”能力数据库连接在业务不活跃的应用中会不断淘汰和重连而连接会通过虚引用方式 com.mysql.jdbc.NonRegisteringDriver$ConnectionPhantomReference携带大量对象如果连接存活时间内YGC次数达到寿命阈值则会进入老年代老年代是使用“标记-清除”算法回收成本更高进而造成FullGC耗时过长。
六、拓展知识点
1、 Druid连接池同样存在不能“保活”问题较新版本提供“KeepAlive”选项未验证
2、 Druid连接池配置的“validationQuery”语句通常并不会被执行MySqlValidConnectionChecker在检查连接有效性时会判断驱动是否实现pingInternal方法如果实现则会通过此方法验证有效性。MySQL的JDBC驱动实现了该方法因此“validationQuery”配置的语句通常不会执行 图5 连接有效性校验代码
3、 DBCP和Druid连接池默认都是FILO如果业务不繁忙会导致只有最前边的连接被使用-归还-使用后边连接基本都在无谓的驱逐、重建连接
4、 虚引用对GC的影响这些引用只有经过两次GC才能被回收掉如果进入老年代则必须经过两次FullGC才能释放内存。本例中由于不断有新的虚引用对象在老年代失效导致FullGC后内存水位仍然偏高会加剧GC压力。新版本JVM已对此做了优化一次GC可以回收掉
5、 类似的影响还有finalize方法
6、 CMS回收器默认MaxTenuringThreshold为6而ParallelGC和G1均默认15
结语
本文对数据库连接失效引起的GC问题进行了详细分析希望读者通过本文对数据库连接“保活”机制、GC问题基本分析方法有所收益后续该系列文章会继续推出其他案例分享。 作者京东零售 王利辉 内容来源京东云开发者社区