肝了两周,线上YGC频繁事故分析

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

高并发场景下很多不确定因素,造成线上机器YGC性能问题。gc耗时长/频繁的原因增加stop-the-world,导致系统可用率降低,影响上下游功能,甚至宕机。

 项目A为提单、商品等提供基础服务, 线上一直平稳。 12.4日,下午4点收到线上大量报警信息。



01
PART
线上异常情况


通过线上监控可以看出, 几秒内最高发生8次ygc,如此频繁的gc造成为上游提供的接口大量超时,线上接口大面积处于瘫痪状态。

肝了两周,线上YGC频繁事故分析

  

首先检查线上JVM参数,通过命令jinfo pid查看jvm配置,-Xmx3072M -XX:NewRatio=2 堆内存3g,年轻代大小为1g。机器4c8g。

-Xms3072M -Xmx3072M -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=8 -XX:NewRatio=2 -XX:SurvivorRatio=8 -server -XX:+UseParNewGC -XX:+UseConcMarkSweepGC  -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSFullGCsBeforeCompaction=2 -XX:+UseCMSCompactAtFullCollection -XX:+CMSScavengeBeforeRemark -server -XX:ParallelGCThreads=4  -XX:ConcGCThreads=4

  

 jvm参数并没有什么不妥,接下来保留线上一台机器,通过 jmap -dump format=b,file=a 命令dump二进制文件,使用内存分析工具MAT 查看当前堆栈信息状况。

  •  sun.misc.Launcher$AppClassLoader :类加载器;

  •  org.apache.ibatis.session.defaults.DefaultSqlSessionFactory:工厂类

  •  org.apache.commons.pool2.impl.GenericKeyedObjectPool:线程池用于调度任务


肝了两周,线上YGC频繁事故分析


    这里发现可疑的地方,GenericKeyedObjectPool 线程池调度缓存连接,线程连接数却有128个,项目A集群有30节点,Redis总连接数128*30=3840个。这意味着线上有大量的线程访问Redis。


肝了两周,线上YGC频繁事故分析


带着这个问题,检查线上线程监控,发现4点22分开始波动,比正常增加150个线程。通过观察ygc监控图和线程数监控图发现 ygc监控折线和线程波动是吻合的。

此外,虚拟机调度700多个线程,cpu负载过高的问题也会随之而来。

肝了两周,线上YGC频繁事故分析


果不其然,紧接着收到cpu利用率报警,大量线程上下文切换,线上cpu使用百分之60以上。


肝了两周,线上YGC频繁事故分析


沿着上面的思路猜测,增加的线程是Redis客户端线程连接,现在Redis客服端一般都是用Jedis, 内部使用线程池管理(不做详细介绍)。那么为什么创建上百个线程呢?



通过查看Redis集群监控,猜测的思路被一步步验证。客户端连接数增加了2000--4000个。


肝了两周,线上YGC频繁事故分析

肝了两周,线上YGC频繁事故分析


上面已经提到过,项目A提供基础的服务,其他工程通过rpc调用获取基本信息。经过一系列内部逻辑的排查和外部api方法检测。其中的一个方法在4点22分开始调用量飙升,达到400k/min的频率。

梳理该方法发现, 这是一个批量接口,提供基础配置信息,数据缓存在Redis中。当前接口调用方在未通知的情况下修改了调用方式。原本是以店纬度获取基本信息, 现在是以店下的品纬度获取基本信息。店下的品有成千上百个, 修改调用方式后调用量就是增加上百倍。


肝了两周,线上YGC频繁事故分析



02
PART
解决问题


至此问题已经找到,为什么会创建如此多的Redis线程呢, 隐约感觉到Redis客户端线程池有问题。

经过一番源码的排查,配置类默认配置:核心线程数量默是128,最大线程是2的32次方-1,队列SynchronousQueue。 

肝了两周,线上YGC频繁事故分析


修改Redis客户端线程池配置,通知上游修改调用方式后,线上回归正常。

    


03
PART
分析总结


合理的运用线程池,看似一行不起眼的代码, 在线上场景中却暴露致命的问题。

遇到线上问题时,要冷静分析因果关系,早先留下坑迟迟没有爆出的问题,在经历版本不断迭代的过程中会暴露出来。要学会利用分析工具, 提升线上实操的能力。

推荐好文

强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

分享一套基于SpringBoot和Vue的企业级中后台开源项目,代码很规范!

能挣钱的,开源 SpringBoot 商城系统,功能超全,超漂亮!

肝了两周,线上YGC频繁事故分析

原文始发于微信公众号(Java笔记虾):肝了两周,线上YGC频繁事故分析