K8S 微服务内存溢出如何排查
oom
场景:晚上做稳定性压测,早上回来发现内存溢出
2022-06-08 08:29:10.273 ERROR 7 — [alina-utility-2] org.apache.catalina.core.StandardServer : Error sending periodic event
java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.concurrent.FutureTask.report(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.FutureTask.get(Unknown Source) ~[na:na]
at org.apache.catalina.core.StandardServer.startPeriodicLifecycleEvent(StandardServer.java:943) ~[tomcat-embed-core-9.0.60.jar!/:na]
at org.apache.catalina.core.StandardServer.lambda$startInternal 0 ( S t a n d a r d S e r v e r . j a v a : 933 ) [ t o m c a t − e m b e d − c o r e − 9.0.60. j a r ! / : n a ] a t j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . E x e c u t o r s 0(StandardServer.java:933) ~[tomcat-embed-core-9.0.60.jar!/:na] at java.base/java.util.concurrent.Executors 0(StandardServer.java:933) [tomcat−embed−core−9.0.60.jar!/:na]atjava.base/java.util.concurrent.ExecutorsRunnableAdapter.call(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.FutureTask.runAndReset(Unknown Source) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor S c h e d u l e d F u t u r e T a s k . r u n ( U n k n o w n S o u r c e ) [ n a : n a ] a t j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . T h r e a d P o o l E x e c u t o r . r u n W o r k e r ( U n k n o w n S o u r c e ) [ n a : n a ] a t j a v a . b a s e / j a v a . u t i l . c o n c u r r e n t . T h r e a d P o o l E x e c u t o r ScheduledFutureTask.run(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[na:na] at java.base/java.util.concurrent.ThreadPoolExecutor ScheduledFutureTask.run(UnknownSource) [na:na]atjava.base/java.util.concurrent.ThreadPoolExecutor.runWorker(UnknownSource) [na:na]atjava.base/java.util.concurrent.ThreadPoolExecutorWorker.run(Unknown Source) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.60.jar!/:na]
at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
Caused by: java.lang.OutOfMemoryError: Java heap space
第一反应就是把服务 dump 下来慢慢分析
进入容器,发现里面没有 jmap 命令,原因是 dockerFile 里的基础镜像使用的是 JRE
# 基础镜像
FROM openjdk:11.0-jre
上 dockerHub 寻找 JDK 镜像 dockerHub java11镜像
发现 JDK 11 镜像太大了
于是选择 11-jdk-oraclelinux7
修改 dockerFile
# 基础镜像
FROM openjdk:11-jdk-oraclelinux7
# 制作人
MAINTAINER njc
# 将工程的jar打包到镜像中
COPY target/app.jar app.jar
# 暴露的端口
EXPOSE 7001
# 镜像启动后执行的命令
ENTRYPOINT java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -jar /app.jar
启动命令加上两个参数
-XX:+HeapDumpOnOutOfMemoryError :表示当JVM发生OOM时,自动生成DUMP文件
-XX:HeapDumpPath=/tmp/heapdump.hprof :表示生成DUMP文件的路径,也可以指定文件名称
调整容器的内存分配,使压测效果更快
Limits :最大值
Reservations :初始值
再次压测,内存溢出时,发现 heapdump.hprof 文件已生成
模糊查询 docker 容器,获取容器 id
docker ps -f name=.*user.*
复制容器里的文件到本地目录
docker cp [容器id]:tmp/heapdump.hprof /root
# docker cp 1a54f6c9011d:tmp/heapdump.hprof /root
终于 dump 下来了,接下来就是分析
java自带工具 jvisualvm,默认路径在 C:\Program Files\Java\jdk1.8.0_291\bin
分析了半天,没找到原因
转用使用 HeapHero heaphero
上传 heapdump.hprof,开始分析
分析第三点大对象,非常清晰,这个接口使用了 JceSecurity 做 RSA 的解密,而 javax.crypto.JceSecurity.verificationResults 这个是静态对象,不能释放,所以就 OOM 了
问题最终在于每次加密都创建一个静态对象,把 static 删除就 ok 了
更多推荐
所有评论(0)