生产告警JVM内存使用率超过80%告警问题排查

背景

  • 我们的产品旨在为金融客户提供全面的解决方案服务,包括资金管理、交易处理等。我们的团队拥有丰富的行业经验和技术实力,能够根据客户的需求定制个性化的解决方案,并提供快速高效的实施和售后服务。 为了确保客户在使用我们的产品时能够获得最佳的体验和服务,公司提供了完善的监控服务。该监控平台可以实时监测产品的运行状态、性能指标,并及时发现和解决问题,保障客户的业务连续性和数据安全。

问题现象

  • 客户反馈在生产过程中出现了"内存使用率过高"的告警。经过检查,我们发现是JVM内存使用率超过了80%。

问题排查过程

  • Why: 首先怀疑是JVM内存配置有问题,因此让客户检查了JVM内存的配置。之前也出现过客户年轻代配置过小,导致很多对象都跑到老年代里面的情况。 Answer: 查看客户配置内存为-Xms:2048M -Xmx:4096 -Xmn:1512m,年轻代和老年代的比例符合1:2的要求,因此排除了这个原因。

  • Why: 接下来只能按照传统的方案导出dump文件进行分析,提供了客户两个命令:

    bash 复制代码
    # 导出dump文件
    jmap -dump:format=b,file=/home/admin/logs/heap.hprof 6214
    bash 复制代码
    # 执行一次full gc后导出dump文件
    jmap -dump:format=live,b,file=/home/admin/logs/heap.hprof 6214

    Answer: 导出两个文件后,发现第一个文件有2G大,但是第二个文件只有400M。因为环境限制就只能让客户把第二个小一点的文件拿下来分析。做这一步主要是用来判断服务是否发生内存泄漏,即存在对象不能释放。文件拿下分析之后发现并没有存在特殊的对象。

  • Why: 通过jprofiler分析了该文件并未找到有内存泄漏后,只能通过jstat去查看内存增长的过程中有没有异常。

    bash 复制代码
    # 间隔5秒钟打印20次服务垃圾回收情况
    jstat -gc 1212 5000 20

    Answer: 通过上述命令,因为监控的原因所以年轻代end区一直有对象创建,然后等到end区满了之后就触发了一次 Minor GC ,存活的对象晋升到了Servivor区;持续这个过程等到一次Minor GC时 Servivor区也满了时,能观察到Old区内存使用量有增长;然后直到Old区内存使用率超过80%仍然未触发full gc释放内存。

  • Why: 此时引申出一个问题,什么情况下会触发full gc? Answer: 通过以下命令主动触发一次full gc后,发现内存果然明显降低了,老年代内存被释放掉了。

    bash 复制代码
    		# 调用java.lang.System.gc()
    		jcmd [pid] GC.run

    因为gc机制跟垃圾收集器有关系,所以需要查看服务使用到的垃圾收集器。命令如下:

    bash 复制代码
    jmap -heap 29871

    通过上述命令看到我们项目使用的正式Java8默认是垃圾收集器,Parallel Scavenge垃圾收集器管理的新生代,ParOldGen表示由Parallel Old管理的老年代。然后就开始搜索Parallel Old相关的配置,网上文章较少,只能从实体书入手,经过阅读《Java虚拟器》后了解到该垃圾收集器并没有限制内存使用率达到多少就必须做full gc,只有CMS垃圾收集器才有这个限制。

问题分析

  • 经过上述排查过程,可以明显看出是监控项设置不合理所导致的问题。建议客户将对应限制调高或关闭以解决这个问题。另外,我们也可以考虑使用其他垃圾收集器来优化性能。

问题总结

  • 经过一整天的排查,我们终于找到了问题所在。然而,这次排查让我意识到了自己在JVM相关知识方面的不足。虽然之前也曾经多次排查过JVM相关的问题,但是一直没有形成完整的知识体系,导致每次都需要重新学习和查找资料。因此,我决定要梳理出一个完整的知识树,以便更好地解决今后工作中遇到的各种问题。
相关推荐
m0_5719575833 分钟前
Java | Leetcode Java题解之第543题二叉树的直径
java·leetcode·题解
魔道不误砍柴功3 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2343 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨3 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
Chrikk4 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*4 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue4 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man4 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
测开小菜鸟4 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity5 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq