前言
有些以前工作时写的博文,没有同步到博客过来。这一篇可能是1年多前写的,希望能给读者一些启示。
首先要介绍下项目的背景。我们的项目是部署到tomcat的,一个tomcat下有若干的Java项目在跑,我们发现在每次重新部署(把war包直接丢进webapps目录下)项目时经常会出现长时间卡顿等现象,并且后续的解决方案一般是重启tomcat。
这个是我做的一次排查尝试。
1. 首先开启tomcat manager界面。
具体步骤为:
- /tomcat/conf/tomcat-users.xml添加:
<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>
- CATALINA_HOME/webapps/manager/META-INF/context.xml,注释远程连接限制:
<Context antiResourceLocking="false" privileged="true" >
<!--
<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
-->
</Context
- 访问 远程主机:8080 点击Manager App:
- 重新部署某个项目,然后点击Find leaks按钮:
- 查看提示是否存在内存泄露:
2. 查看服务器状态
查看内存状态:
3. 配置 JMX
无密码
- 编辑 /tomcat/bin/setenv.sh
#!/bin/sh
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=120.25.205.78 -Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.port=18889"
#JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management. j mxremote.password.file=../conf/jmxremote.password -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access -Dcom.sun.manag em ent.jmxremote.port=18889"
注意首先 hostname必须是IP,其次不能是127.0.0.1。如果是虚拟机之类的,可以使用内网地址也就是类似于192.168.1.3之类的。 云服务器之类的填外网地址。
- 重启tomcat。
有密码
- 编辑 /tomcat/bin/setenv.sh
#!/bin/sh
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=xxx -Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management. j mxremote.password.file=../conf/jmxremote.password
-Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access
-Dcom.sun.management.jmxremote.port=18889"
- 创建/编辑 /tomcat/conf/jmxremote.password 账号 权限
monitorRole readonly controlRole readwrite
- 创建/编辑 /tomcat/conf/jmxremote.access 账号 密码
monitorRole tomcat
controlRole tomcat
- 修改读写权限:
chmod 600 jmxremote.access
chmod 600 jmxremote.password
- 重启tomcat
故障分析
可以借助Telnet看端口是否能用。不能用的话看看防火墙之类的问题。
4. 配置 jstat
- 确认环境变量JAVA_HOME是否存在。和jdk安装方式有关系。
export | grep JAVA_HOME
- 有输出代表有这个变量,那么下一步我们要创建一个jstatd.all.policy文件。
mkdir -p /etc/java/
cd /etc/java/
(sudo) vim jstatd.all.policy
- 编辑文件jstatd.all.policy,可以看到之所以要确认是否有JAVA_HOME是为了文件内容的引用。
grant codebase "file:${java.home}/../lib/tools.jar" {
permission java.security.AllPermission;
};
- 启动
jstatd -J-Djava.security.policy=jstatd.all.policy -J Djava.rmi.server.hostname=xxx &
5. 分析Tomcat 日志
问题:
A web application appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak.
解决:
-
升级mysql-connector-java
-
引入
@Component public class ShutdownListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { } @Override public void contextDestroyed(ServletContextEvent sce) { AbandonedConnectionCleanupThread.checkedShutdown(); } }
参考:https://bugs.mysql.com/bug.php?id=69526
热部署现象
用visualvm观察部署一个存在内存泄露的项目: