• 记录一次典型oom的处理过程


    背景

    有同学反馈收到应用RT的报警,其中的流量都来自于网关集群中的一台机器。因为负责网关,就上去看了下并进行排查。整体是一个比较明显的oom,这里只是记录下排查过程,老司机可以略过了。

    初步现象

    常规步骤,使用top 和jstat -gcutil 能直观的看到在拼命full gc。推测是出现了oom。
    在这里插入图片描述

    初步排查

    一开始是用 jmap -histo:live [pid] >a.log 导出当前内存对象,为什么没有直接用jmap -dump:live 也是想偷懒,因为-dump 生成的文件太大,我们的服务器又跑在k8s上面,要拿回本地需要通过ftp 中转,想着能省就省。结果发现这个给后面埋了个大坑。
    在这里插入图片描述
    基于上面的结果,一度怀疑是sentinel 引起的问题。特别是对比了正常的机器上的内存分布
    在这里插入图片描述
    在上面浪费了大量时间,后面回过头看其实ConcurrentHashMap 占比这么高说明是缓存管理出现了问题。

    进一步排查

    老老实实用 jmap -dump:live,format=b,file=xxx.xxx [pid] 打印出详细的内存堆栈,拿到本地后用 IBM HeapAnalyzer(比较轻量) 或者MAT(大&慢,但是好用) 打开分析。
    这里是先用了IBM HeapAnalyzer 进行分析。
    在这里插入图片描述
    从上面比较直观看到出现oom的类。这里只是看到单个的类比较大,从源码上看:在这里插入图片描述
    会发现有块缓存没有设置长度和失效时间,这个很可能是导致oom的原因。

    线上出现了新的问题

    过了个周末,周一到公司之后同事反馈又出现了oom,还以为没解决上面的问题。于是又来了一遍,把内存dump 下来分析。
    在这里插入图片描述
    可以看到这次出现的类跟之前已经不一样了。这个时候发现 IBM HeapAnalyzer 的一个弱项,他不能直接显示字段名,只能显示类名,这个跟另一个同事使用的在线工具:https://heaphero.io/heap-index.jsp 有明显区别。但是在线工具打开dump 文件非常慢。这个时候就想着用MAT 打开看看。
    下载MAT 打开官网:https://eclipse.dev/mat/downloads.php ,这个时候浏览器提示非安全的,又去找了下解决方法。
    下载安装好之后,打开提示需要jdk1.17 ,我本地是1.11 。又去下了jdk1.17(https://www.oracle.com/java/technologies/downloads/#jdk17-mac),因为不想破坏本地jdk环境,所以需要配置MAT
    在这里插入图片描述
    增加2行,配置下载到本地的jdk路径

    -vm
    /Users/ykdsg/opensource/jdk-17.0.8.jdk/Contents/Home/bin/java
    
    • 1
    • 2

    然后编辑 MemoryAnalyzer.ini 文件
    在这里插入图片描述
    新增配置
    在这里插入图片描述
    顺便改下jvm的内存,因为dump 文件通常比较大,太小的内存很容易报错。
    调整完之后就可以顺利打开了。
    在这里插入图片描述
    可以比较直观的看到字段名。
    在这里插入图片描述
    可以推测是Map的value 类型是List,导致数据重复的增加。
    在出现问题的机器上用arthas的getstatic 来看下内部情况:
    先用arthas 连上jvm:

    java -jar /alidata/deploy/arthas-boot.jar 45
    
    • 1

    再用getstatic 查看静态字段,-x 2 表示对象下钻的层级

    getstatic com.yangt.hop.biz.util.DubboServiceCacheUtils serviceNameKeyMap -x 2
    
    • 1

    确实出现很多重复的数据,同一个key里面的值太多了,都打不下了:
    在这里插入图片描述

    最终解决

    找到问题之后的解决方案就比较简单了,将List类型改为Set 就能解决这个问题。fix 之后再来看下这个字段的情况:
    在这里插入图片描述
    可以看到每个key 对应的数据基本就1条。

    总结

    如果要分析oom 还是老老实实用jmap -dump:live 以及配合MAT,大有大的用处。如果dump 的文件太大,本地内存吃紧的话可以考虑在服务器上建立索引,这个有看到过介绍但没试过。
    arthas 是个好工具,对线上问题简直居家旅行必备。
    对于缓存:如果是自己管理,并没有通过guava 之类的框架,还是要小心谨慎,并且尽量避免用list等非去重的结构。

  • 相关阅读:
    解读提示工程(Prompt Engineering)
    挑战视觉边界,探索图形验证码背后的黑科技
    判断当前Activity是否有DialogFragment显示
    【Python Web】Flask框架(七)jQuery类库
    20天学习Spark(0)之最简单版Spark入门
    前端学习线路+学习资料 持续补充
    面试必问:Redis 如何实现库存扣减操作?
    111个Python数据分析实战项目,代码已跑通,数据可下载
    活动预告丨EMNLP 2022半监督和强化对话系统研讨会12月7日线上召开!
    【CV】第 2 章:使用本地二进制模式的内容识别
  • 原文地址:https://blog.csdn.net/ykdsg/article/details/133844461