JVM第六讲:线上环境 FGC 频繁,如何解决?

简介: JVM第六讲:线上环境 FGC 频繁,如何解决?

1、问题背景

我们的服务遇到线上环境 FGC 频繁时,我们是如何解决的。

2、遇到的问题及解决方案

2.1、pinpoint 打点存在大批量300ms以上
  • 排查方向
  • 检查db是否存在慢sql
  • 定位调用链中具体接口
  • pinpoint inspector查看是否存在fullGC
  • 应用dubbo线程池是否耗尽(默认200个线程)
  • 打点存在大批量红点
  • 排查方向:确认红点出现源头,判断自己调用其他的业务服务是否存在超时)
  • 重启应用
2.2、应用 cpu 突然升高
  • 排查方向:
  • 应用是否存在fullGC
  • 检查应用流量是否突增
  • 是否存在不合理调用(可参考监控大盘)
  • 1、阈值标准
  • pinpoint最近5min出现大批量超过5s以上的打点
  • 应用cpu 90%以上持续3min
  • 应用内存90%以上持续3min(瞬间暴增除外)
  • 收到上游最多两个以上业务方反馈
  • 2、解决措施:
  • 打印线程栈:jstack l <路径文件名.bin>
  • dump jvm堆 jmap dump:format =路径文件名.bin
  • 重启应用:运维执行命令/jenkins
  • 下游业务服务方响应超时
  • sentinel consumer限流
  • 如果存在恶意攻击是,联系安全部门拦截
  • 如果单业务流量大,针对url或dubbo进行限流
  • 升级应用机器配置(一般是加机器)
2.3、内存升的很快
  • 排查方向:
  • 1、排查是否存在新版本发布的影响;
  • 2、查询下调用频率较高的接口是否存在内存缓存的使用;
  • guava cache 和 caffeine cache
  • 3、查询下日志确定应用是否存在大批量的异常抛出
  • 2、解决措施:
  • 打印线程栈:jstack l <路径文件名.bin>
  • dump jvm堆 jmap dump:format =路径文件名.bin
  • 重启应用:运维执行命令/jenkins
  • 下游业务服务方响应超时
  • sentinel consumer限流
  • 如果存在恶意攻击是,联系安全部门拦截
  • 如果单业务流量大,针对url或dubbo进行限流
  • 升级应用机器配置(一般是加机器)
2.4、数据库 cpu持续90%以上10分钟
  • ops是否明显增高(是否爬虫等异常流量)
  • 是否存在大批量数据查询(索引/动态sql)
  • 阈值标准:
  • 数据库cpu100%持续2min且没有下降趋势
  • 链接数一直增加没有下降的趋势,iops打满且没有下降的趋势
  • 内存使用率80%以上持续5min,
  • 解决措施
  • 定向业务限流
  • 运维kill慢sql
  • 运维kill锁进程
  • 重启应用
  • 升级配置(但是需要考虑升级时间的影响问题)
2.5、连接数线性增高且长时间不下
  • 查看是否存在慢sql
  • 查看应用的数据库连接池配置
  • 查看数据库中是否存在死锁 show engine innodb status;
  • 解决措施
  • 定向业务限流
  • 运维kill慢sql
  • 运维kill锁进程重启应用
  • 升级配置(但是需要考虑升级时间的影响问题)
2.6、iops飙高
  • ddl操作
  • 是否针对大表新增索引
  • 是否存在变更大表字段,业务上是否存在大批量操作(写入或读取)
  • 解决措施
  • 定向业务限流
  • 运维kill慢sql
  • 运维kill锁进程
  • 重启应用/升级配置(但是需要考虑升级时间的影响问题)
2.7 内存升高
  • 确认下数据库连接数是否异常(连接也占用内存)
  • 解决措施
  • 定向业务限流
  • 运维kill慢sql
  • 运维kill锁进程
  • 重启应用/升级配置(但是需要考虑升级时间的影响问题)
2.8、中间件 MQ 消息堆积
  • 基本不需要处理
2.9 canal delay延时高
  • 排查方向:
  • 大批量数据操作,是否存在和其他业务共用canal,受其他业务影响
  • 阈值标准:garafa canal delay 延迟超过用户不可接受的范围
  • 解决措施:业务评估无影响情况下联系运维重置消费位点
2.10、线上环境 FGC 频繁
1、明确分工

这个步骤应该是在事前就已经明确好的,类似于一个故障处理流程规范,这边需要明确出3个主要角色:

1)总指挥

  • 负责故障处理整体指挥的人,例如快速拉起线上/线下会议、通知到系统核心同学,对各同学工作进行分工等等。
  • 该角色一般由主管来担任,或者主管指定的另一个同学。

2)故障恢复小组

  • 负责故障恢复的同学,该部分同学的任务就是让系统以最快的速度恢复正常。

3)故障定位小组

  • 负责故障定位的同学,该部分同学的任务就是定位出问题的根本原因。
  • 大部分同学的回答可能会集中在故障定位中,但其实另外两个角色也是非常重要的,在线上出现问题时,止损永远是放在第一位,其次才是定位。
2、故障恢复

2.1、线上发布导致

  • 查看故障服务近期是否存在上线操作,如果有的话优先采取回滚解决。
  • 分析:该场景应该是最常见的场景,就是刚上的代码存在bug。

2.2、非线上发布导致

1)小面积故障

  • 如果故障机器只是发布在少量机器,例如:某机台机器、某个机房机器、某个地域的机器、某个泳道的机器等等。
  • 此时优先采取禁用服务器解决,禁用前先评估禁用这批机器后是否存在服务容量问题,如果是则先扩容。
  • 分析:该场景一般是代码存在bug,但是该场景的使用频率很低,所以上线时没暴露出来,只是偶尔会被触发到。也是出现概率比较大的场景。

2)大面积故障

  • 如果故障机器不存在共性,这个概率说实话非常非常小,但是如果碰到了,故障恢复小组能做的事情就比较有限了。
  • 因为这个场景大概率是代码存在bug,同时发布时没有被大量触发,而是到现在才被大量触发,需要定位才能根本解决。
  • 此时,故障恢复小组能做的就是使用扩容、重启、限流等手段,来尽量维持服务的运转,同时给故障定位争取时间。
  • 分析:之所以说该场景概率小是因为,分布在大量机器上的故障通常是使用频率高的场景,这部分场景一般在服务发布时就会暴露出问题,而不是发布很久之后。但是这个场景也是确实存在的,但是会比较少。
3、故障定位

故障定位主要是用于应对故障恢复中的最后一个场景,也是将故障恢复和故障定位分成两个小组并行执行的主要原因。

3.1、FGC 能正常回收到内存

  • 通过监控或GC日志,我们能看到每次FGC后都能正常回收到内存,但是内存很快又被占满,导致又出现FGC,从而出现FGC频繁。

这个场景通常可能由于两个原因导致:

  • 1)Eden 区配置太小,导致大量对象直接进入老年代,从而导致老年代快速被占满。
  • 2)业务量较大,特别是在业务高峰期。而当前的服务器配置已经无法满足当前的业务量。

对于这两个原因,代码本身可能没有大问题,优先采取扩容机器,降低单台服务器压力即可解决。

后续则需要重新评估当前服务器的配置是否满足当前的业务量,JVM参数是否存在优化空间等等。

  • 分析:该场景是由于业务量增大没有及时评估或者JVM参数配置存在问题导致的,整体来说,出现的概率较小。

3.2、FGC 不能正常回收到内存

  • 通过监控或GC日志,我们能看到每次FGC后只能回收到很小的空间,甚至回收不到空间,从而出现FGC频繁。
  • 对于这个场景,二话不说,先dump下内存,使用工具看下当前的内存泄漏情况、内存分布情况等等,查看是哪个对象占用了大量内存。具体工具常见的例如 Eclipse MAT,如果公司内部有封装的工具就更好了。
  • 通常查看完内存占用情况,大概率会看到个别对象占用了大量的内存,结合其引用链定位出在代码中的位置。

接着就是根据代码分析问题的严重程度:

  • 如果是小概率触发的场景,大部分请求其实正常,则可以先禁用问题机器,后续上线修复即可。
  • 如果是大概率触发的场景,则查看是否存在降级开关,如果有则优先降级解决,如果没有则只能修改代码,走紧急修复流程。

总结

  • 整体的解决流程其实还是比较简单的,没有太复杂的东西。大多数情况下,用好扩容、禁用、重启这几个常见手段即可解决大部分问题。
  • 个人经验而言,线上频繁FGC问题90%以上是由于开发同学代码存在问题导致的,例如常见的存在死循环、开无界队列等等。以上的问题在dump后,很容易就能定位到根本原因。
  • 而如果遇到诸如依赖的第三方jar存在bug导致的问题,例如Guava、Log4j,这种场景一般是在极端情况下出才会出现,所以一般只会出现在少数机器,禁用即可临时解决,然后后续再慢慢排查。
相关文章
|
2月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
69 3
|
7月前
|
监控 Java 测试技术
滚雪球学Java(45):探秘Java Runtime类:深入了解JVM运行时环境
【5月更文挑战第20天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
61 1
滚雪球学Java(45):探秘Java Runtime类:深入了解JVM运行时环境
|
7月前
|
存储 分布式计算 前端开发
jvm性能调优实战 - 26一个每秒10万并发的系统如何频繁发生Young GC的
jvm性能调优实战 - 26一个每秒10万并发的系统如何频繁发生Young GC的
150 0
|
7月前
|
存储 SQL Java
jvm性能调优实战 - 27亿级数据量的实时分析引擎,为啥频繁发生Full GC
jvm性能调优实战 - 27亿级数据量的实时分析引擎,为啥频繁发生Full GC
104 0
|
Java
JVM GC频繁优化
JVM GC频繁优化
200 0
|
监控 Java 数据安全/隐私保护
JVM频繁GC内存溢出排查
GC(Garbage collection)频繁和堆内存溢出原因简单来说是对象占用堆空间难以回收,新对象无法分配触发GC或者直接导致内存溢出,最终进程结束。
480 0
|
运维 监控 Java
MyBatisPlus的in方法入参数量过多导致的JVM频繁FullGC案例
MyBatisPlus的in方法入参数量过多导致的JVM频繁FullGC案例
737 0
MyBatisPlus的in方法入参数量过多导致的JVM频繁FullGC案例
|
负载均衡 Java 微服务
从JVM角度思考--如何预估线上环境机器资源大小
如何给JVM虚拟机巧妙地设计参数对大部分开发来说一直是个随缘的事情,可能是去网上拷贝一套参数,可能是沿用公司其他应用的参数。但是这个随缘的操作可能就会给未来留下隐患。给JVM分配的内存过大倒是没什么问题,无非浪费点资源,但是如果分配的内存过小,就有可能导致频繁的Full GC,给人一种系统一直很卡的感觉。这篇文章就通过一个实例分析一下如何结合场景设置JVM虚拟机参数。 当然,本文更重要的是希望能通过预估参数的这个过程,让你更加了解虚拟机内部的一些东西,要想最准确的参数设置,用一些工具记录下JVM各个区域的变化会更有效。
|
监控 Java Linux
jvisualvm分析linux环境下jvm内存溢出
jvisualvm分析linux环境下jvm内存溢出
393 0
jvisualvm分析linux环境下jvm内存溢出
|
缓存 Java
JVM频繁fullgc优化策略
JVM频繁fullgc优化策略
179 0