问题场景:
现象:有一次发现容器里面启动的java项目探活每过一段时间(大概半小时)就失败,导致项目在容器中重复的重启,服务时好时断。
问题描述
在容器中排查问题的时候发现了两个问题:
- 进入容器查看启动日志发现,项目启动之初是能够正常运行并且访问的。在经过一段时间后就出现了
OOM
,导致项目被hang住了,一直在进行Full GC
,最终无法访问。
- 在这个情况下,本来想通过
jstack
命令去看看栈的情况,却收到提示Unable to get pid of LinuxThreads manager thread
问题2原因分析:
先分析解决第二个问题,才能更好的探查第一个问题。通过查阅资料发现,无法使用jstack命令的原因是因为,在容器启动的时候java启动命令作为容器的ENTRYPOINT
而启动的,使得启动项目的进程为容器的1号进程(init进程),所以无法使用jstack
查看程序的栈情况。【容器的拓展知识】
ENV OPTS=" -javaagent:/jacocoagent_skip_slb-0.8.6.jar=includes=*,output=tcpserver,port=8901,address=*,append=false -Xverify:none -javaagent:/skywalking-agent/skywalking-agent.jar -Dspring.profiles.active=test -Dspring.application.name=passport -verbose:gc -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
COPY ./git-resource/target/*.jar /app.jar
ENTRYPOINT ["sh", "-c", "java $OPTS -jar /app.jar"]
问题2解决方案:
为了解决无法使用jstack的问题,只能曲线救国,不用java启动命令作为容器的启动命令。将项目启动命令放到shell
脚本中,再用sh -c
启动容器,这样shell脚本pid就会为1。【拓展:容器启动命令ENTRYPOINT和CMD详解】
ENV OPTS=" -javaagent:/jacocoagent_skip_slb-0.8.6.jar=includes=*,output=tcpserver,port=8901,address=*,append=false -Xverify:none -javaagent:/skywalking-agent/skywalking-agent.jar -Dspring.profiles.active=test -Dspring.application.name=passport -verbose:gc -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy"
RUN echo 'java $OPTS -jar /app.jar' > ./entrypoint.sh
RUN chmod 777 ./entrypoint.sh
COPY ./git-resource/target/*.jar /app.jar
ENTRYPOINT ["sh", "-c", "./entrypoint.sh"]
问题1原因分析:
解决了问题2后,上容器使用jps + jstack
查看栈情况发现有很多:java.lang.Thread.State: BLOCKED
的线程,在等待获取锁0x00000000e1455ca0
。继续往下看发现,在使用mybatis查询数据库的时候被sentinel限流拦截了。想起近期因为总部不再支持sentinel,导致查询数据库连接数一直被占用,没被释放,时间长了就使得程序oom
问题1解决方案:
去掉pom文件中对sentinel的引用,最后就能正常运行了