maxLifetime导致fullgc stw耗时长

背景

核心服务、并发较高,查询接接口最高几万qps 对停顿比较敏感

jvm

  • par new + cms、 堆分配较大,老年代6g、old gc水位 3G左右
  • ygc几分钟一次、full gc 十天一次

分库分表,对应多个数据库连接池对象

问题发现

stw告警,full gc stw超过500ms

查看jvm gc曲线图,old space一直慢慢上升,有内存泄露的感觉,但是fullgc后能回收掉

gc日志发现 cms最后一个阶段 final remark 时候耗时较久(需要加上参数 -XX:+PrintReferenceGC 才能打印具体什么类型的引用)

dump heap 发现有大量 finalizer ,内部都是 pgconnection 数据库连接对象

如何解决

  • 该服务使用的是pgsql,不会像mysql那样在数据库服务侧关闭 8小时空闲的连接,所以不需要 maxLifetime 在此之前(7小时)提前去重建, 置为 maxLifetime = 0 关闭该机制
  • 同时连接池 minimumIdle 根据qps计算下来不需要那么大,适当调小

根因分析

其实maxLifetime 机制本身没什么问题

maxLifeTime = 7 小时,当它清理连接的时候,gc age肯定是超过15的老对象了,要进入老年代

假设连接多个数据库 n, db连接池 minimumIdle = m,那么每隔 maxLifetime 就会有 T = m * n * maxLifeTime 个连接进入老年代, 案例里 m=8 , n=35, maxLifeTime=7小时,fullgc 大概10天一次

那么full gc 的时候大概有 8 * 35 * (10天 * 24 /maxLifeTime) = 9600个连接对象在老年代 非常多

连接的库越多、连接池min个数设置越大、fullgc间隔时间越长(老年代空间越大),那么 cms final remark 暂停就越久; 如果数据库选用的mysql,最好保留maxLifeTime机制,合理设置minimumIdle ,同时 jvm 堆大小不能一味的往大了设置,太大会导致 ygc、fullgc耗时变长

posted @ 2021-04-16 00:54  mushishi  阅读(936)  评论(0编辑  收藏  举报