背景
我们的springboot项目是通过k8s部署的,我们使用了G1垃圾回收器作为jvm的垃圾回收器,同时也配置了如下的各种应对jvm oom崩溃时的参数;在服务上线的一周左右时间,我们发现这个服务出现了oom重启,于是开启了我漫长的问题追踪过程;
-XX:+UseG1GC -XX:MaxGCPauseMillis=50
-XX:InitiatingHeapOccupancyPercent=45
-XX:+ParallelRefProcEnabled
-XX:+DisableExplicitGC
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/app/logs
-XX:+PrintAdaptiveSizePolicy
-XX:+PrintTenuringDistribution
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCDateStamps
-Xloggc:/app/logs/gc.log
1、从websocket开始
由于我们的业务使用了websocket,并且通过websocket传输给springboot大对象(MB级别),于是乎怀疑是不是前端操作太频繁,导致堆内存溢出了,但难搞的是服务oom的时候没有内存dump日志,所以只能实时观察了
1.1、上工具
网络上很多可以查看jvm虚拟机的工具,包括想arthas、visualvm等等,或者你也可以自己使用jmap、jstat等等命令来观察,具体命令可以问一下chatgpt;我个人偏爱jprofiler这款工具(简单直观、功能强大),于是开始搭建jprofiler,本地先安装好jprofiler(自行破解),然后需要在pod镜像里边加上相关agent和so文件外加启动命令,才能远程查看;agent和so文件下载地址如下(注意和你安装的版本保持一致,比如你安装的jprofiler是12.0.4,那么你应该下载12.0.4版本的agent和so文件):https://www.ej-technologies.com/download/jprofiler/files
从这个地址里边找到linux系统的包,下载下来;把里边的红框的两个文件,拷贝到你的java项目的对应目录下,如下图;


然后编写Dockerfile的时候把这个目录加到镜像里面去,如下
ADD bin/jprofiler /app/jprofiler
在java启动脚本上加上
-agentpath:/path/to/libjprofilerti.so=port=8849,nowait
再在service里边配置nodePort,target指向这个8849,外部暴露一个nodePort就搞定了;
打开你的jprofiler,链接你的nodePort ip和端口