tomcat与jvm的关系分析

首先,我们来看几个概念:

1. 什么是jvm

我们从操作系统的层面来理解,jvm其实就是操作系统中的一个进程。既然是一个进程,那么我们很容易的可以通过任务管理器来查看。假设此时我们启动myeclipse(myeclipse其实就是用java语言编写的一个软件,他的运行必然会启动一个jvm,我们可以把myeclipse理解成我们自己写的一个简单的java版的helloworld程序)。查看任务管理器的截图如下:

未分类

2. 什么是tomcat

tomcat其实是一个用java语言开发的免费开源的web服务器(因为是java语言开发,这就是为什么使用tomcat前要配置好jdk,因为jdk里面有jvm,而运行java应用需要jvm)。此时再次查看任务管理器会发现多了一个javaw.exe

看了两者之间的概念之后,相信我们都清楚了两者之间的关系。

现在还有一个问题:

同一个tomcat下的java ee项目使用的是不是同一个jvm?答案是是的。(使用的都是启动tomcat的jvm)这个可以通过启动不同的web应用来自己判断。

如果运行的是普通的java se程序,使用的是不是同一个jvm呢?答案是否。这个可以自己运行程序判断。(可以写一个很简单的while死循环,便于查看)。

Zabbix监控(JVM):Tomcat

Zabbix3.4.0通过JVM监控Tomcat

一、安装zabbix

参考:
https://www.jianshu.com/p/5b6541681700

二、配置Tomcat JMX

编辑catalina.sh,加入如下配置

CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote #开启远程监控
-Dcom.sun.management.jmxremote.port=12345 #远程监控端口
-Dcom.sun.management.jmxremote.ssl=false #远程ssl验证为false
-Dcom.sun.management.jmxremote.authenticate=false #关闭权限认证
-Djava.rmi.server.hostname=192.168.9.74" #部署了tomcat的主机地址

重启tomcat

验证是否启动JMX监听成功

[root@localhost tomcat6]# lsof -i:12345
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
java    26944 root   18u  IPv6 4076076      0t0  TCP *:italk (LISTEN)

至此,Tomcat已经支持JMX.

三、配置zabbix_server

Zabbix通过JMX监控Tomcat的对应关系:
zabbix_server开启java poller, zabbx_java开启JavaGateway,端口为10052,Tomcat JMX开启12345提供性能数据。
数据获取:java pollerJavaGateway:10052Tomcat:12345.

zabbix_server:默认未启用JavaPollers,
启用JabaPollers,编辑/usr/local/zabbix/etc/zabbix_server.conf,加入三行代码:

JavaGateway=127.0.0.1
JavaGatewayPort=10052
StartJavaPollers=5

重启zabbix_server.
zabbix_java:按照步骤一安装可直接启动zabbix_java(安装编译中带了–enable-java参数),
启动路径参考:/usr/local/sbin/zabbix_java/startup.sh
rpm包安装gateway,需要java,java-devel依赖

安装yum源:yum install -y http://repo.zabbix.com/zabbix/2.4/rhel/6/x86_64/zabbix-release-2.4-1.el6.noarch.rpm
安装gateway:yum install -y  java  java-devel  zabbix-java-gateway 

检查启动情况

[root@portal zabbix_java]# lsof -i:10052
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
java    27021 root   12u  IPv6 5221678      0t0  TCP *:10052 (LISTEN)

Tomcat JMX:按照步骤二安装没问题可略过

四、zabbix监控端web界面配置

主机增加JMX接口

①进入后台,configuration(配置)->hosts(主机)->选择你的主机->找到这一项jmx interface(JMX接口) 点击add,输入对应的tomcat ip地址和jmx端口

②点击主机的模版选项,添加以下两个模板

[Template App Apache Tomcat JMX]
[Template App Generic Java JMX]

点击添加,然后更新。

启动jenkins时指定jvm参数

环境

java:1.7
jenkins:2.5
操作系统:win7
服务器:centos6
工具:CRT

场景

今天jenkins用着用着报了以下错误(从日志中查看):

javax.servlet.ServletException: org.apache.commons.jelly.JellyTagException: jar:file:/home/jenkins/war/WEB-

INF/lib/jenkins-core-2.25.jar!/lib/layout/layout.jelly:83:72: <st:include> Error setting property 'page', 

exception - java.lang.OutOfMemoryError: PermGen space
        at org.kohsuke.stapler.jelly.JellyFacet$1.dispatch(JellyFacet.java:103)
        at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:746)
        at org.kohsuke.stapler.Stapler.invoke(Stapler.java:876)
        at org.kohsuke.stapler.Stapler.invoke(Stapler.java:649)
        at hudson.init.impl.InstallUncaughtExceptionHandler$1.reportException

(InstallUncaughtExceptionHandler.java:30)
        at org.kohsuke.stapler.compression.CompressionFilter.reportException(CompressionFilter.java:77)
        at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:55)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
        at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:82)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
        at org.kohsuke.stapler.DiagnosticThreadNameFilter.doFilter(DiagnosticThreadNameFilter.java:30)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
        at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:553)
        at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
        at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
        at org.eclipse.jetty.server.Server.handle(Server.java:499)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
        at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
        at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)
Caused by: org.apache.commons.jelly.JellyTagException: jar:file:/home/jenkins/war/WEB-INF/lib/jenkins-core-

2.25.jar!/lib/layout/layout.jelly:83:72: <st:include> Error setting property 'page', exception - 

java.lang.OutOfMemoryError: PermGen space
        at org.apache.commons.jelly.impl.TagScript.handleException(TagScript.java:726)
        at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:281)
        at org.apache.commons.jelly.TagSupport.invokeBody(TagSupport.java:161)
        at org.apache.commons.jelly.tags.core.ForEachTag.doTag(ForEachTag.java:150)
        at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:269)
        at org.apache.commons.jelly.tags.core.CoreTagLibrary$1.run(CoreTagLibrary.java:98)
        at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
        at org.apache.commons.jelly.tags.core.CoreTagLibrary$1.run(CoreTagLibrary.java:98)
        at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
        at org.apache.commons.jelly.tags.core.CoreTagLibrary$2.run(CoreTagLibrary.java:105)
        at org.kohsuke.stapler.jelly.CallTagLibScript.run(CallTagLibScript.java:120)
        at org.apache.commons.jelly.impl.ScriptBlock.run(ScriptBlock.java:95)
        at org.apache.commons.jelly.tags.core.CoreTagLibrary$2.run(CoreTagLibrary.java:105)
        at org.kohsuke.stapler.jelly.JellyViewScript.run(JellyViewScript.java:95)
        at org.kohsuke.stapler.jelly.DefaultScriptInvoker.invokeScript(DefaultScriptInvoker.java:63)
        at org.kohsuke.stapler.jelly.DefaultScriptInvoker.invokeScript(DefaultScriptInvoker.java:53)
        at org.kohsuke.stapler.jelly.JellyFacet$1.dispatch(JellyFacet.java:95)
        ... 29 more
Caused by: java.lang.IllegalArgumentException: Error setting property 'page', exception - 

java.lang.OutOfMemoryError: PermGen space
        at org.apache.commons.beanutils.ConvertingWrapDynaBean.set(ConvertingWrapDynaBean.java:74)
        at org.apache.commons.jelly.impl.TagScript.run(TagScript.java:265)
        ... 44 more
Caused by: java.lang.OutOfMemoryError: PermGen space

十一月 29, 2017 10:45:57 上午 org.eclipse.jetty.util.log.JavaUtilLog warn
警告: Could not send response error 500: javax.servlet.ServletException: 

org.apache.commons.jelly.JellyTagException: jar:file:/home/jenkins/war/WEB-INF/lib/jenkins-core-

2.25.jar!/lib/layout/layout.jelly:83:72: <st:include> Error setting property 'page', exception - 

java.lang.OutOfMemoryError: PermGen space

可以很明显看出是内存溢出;

官网也给出了解决办法:

修改jvm参数

我们先来看看官方是怎么解释(为什么会内存溢出):

As your project grows, and you use new tools to either build or analyze your code, you will inevitably exceed the memory settings which your JVM provides by default. This is especially true on 64 bit JVM’s since they double the size of the reference pointer. This page aims to show you how to increase the memory available to your build process.

上面的意思是:

随着我们项目的增长,和使用新的工具去构建或分析代码,会不可避免的超过jvm提供的默认值。这在64位jvm中尤为明显,因为它们引用的指针大小是翻倍的(相对32位)。接下来将展示如何增加可用于构建过程的内存(通俗点说就是增加 jvm 可用的内存)。

Heap or Permgen

内存溢出分来两种;

官方介绍:

There are two OutOfMemoryErrors which people usually encounter. The first is related to heap space: java.lang.OutOfMemoryError: Heap space When you see this, you need to increase the maximum heap space. You can do this by adding the following to your JVM arguments -Xmx200m where you replace the number 200 with the new heap size in megabytes. 
The second is related to PermGen: java.lang.OutOfMemoryError: PermGen space. When you see this, you need to increase the maximum Permanent Generation space, which is used for things like class files and interned strings. You can do this by adding the following to your JVM arguments -XX:MaxPermSize=128m where you replace the number 128 with the new PermGen size in megabytes.

意思就是:

通常情况下,我们会遇到两种内存溢出的错误。第一种是关于堆溢出:java.lang.OutOfMemoryError: Heap space;当你看到这个错误时,你需要增加堆空间的最大值。你可以添加以下内容作为jvm的参数:-Xmx200m,数字200你可以使用新值替换。比如4096即:-Xmx4096m。
第二种是关于永久代的(java7以后版本会移除永久代):java.lang.OutOfMemoryError: PermGen space。当你看到这个错误时,你需要增加永久代空间的最大值,这个空间是被像 类文件和interned字符串所使用的。你可以添加以下内容作为jvm的参数:-XX:MaxPermSize=128m,数字128你可以使用新值替换。比如512即:-XX:MaxPermSize=512m。

我的改法

很明显我的问题是第二种,所以我需要使用-XX:MaxPermSize=128m这个参数:

我的改法是:

vim /etc/sysconfig/jenkins
# 找到 JENKINS_JAVA_OPTIONS
# JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true"
# 改为
JENKINS_JAVA_OPTIONS="-XX:MaxPermSize=512m -Djava.awt.headless=true"

保存好后,之后,在重启jenkins。但是呢我启动后,还是报内存溢出,连页面都打不开。看了下进程:

[root@master01 log]# ps -ef | grep jenkins
root       357 45410  0 11:06 pts/4    00:00:00 grep jenkins
root     22293     1  0 Nov13 ?        00:54:21 /usr/java/jdk1.7.0_51/bin/java -cp /home/jenkins/dataspace/plugins/maven-plugin/WEB-INF/lib/maven32-agent-1.12-alpha-1.jar:/home/activemq/apache-maven-3.2.3/boot/plexus-classworlds-2.5.1.jar:/home/activemq/apache-maven-3.2.3/conf/logging jenkins.maven3.agent.Maven32Main /home/activemq/apache-maven-3.2.3 /var/cache/jenkins/war/WEB-INF/lib/remoting-2.62.jar /home/jenkins/dataspace/plugins/maven-plugin/WEB-INF/lib/maven32-interceptor-1.12-alpha-1.jar /home/jenkins/dataspace/plugins/maven-plugin/WEB-INF/lib/maven3-interceptor-commons-1.12-alpha-1.jar 48531
root     24012     1  0 Nov21 ?        01:38:52 /usr/java/jdk1.7.0_51/bin/java -Dcom.sun.akuma.Daemon=daemonized -Djava.awt.headless=true -DJENKINS_HOME=/home/jenkins/dataspace -jar /home/jenkins/lib/jenkins.war --logfile=/home/jenkins/log/jenkins.log --webroot=/home/jenkins/war --daemon --httpPort=7080 --ajp13Port=-1 --debug=5 --handlerCountMax=100 --handlerCountMaxIdle=20

这里我们看到进程id:22293,这个进程估计是我之前启动一个maven job依赖下来的,这个maven项目每次启动都把jenkins直接跑崩了!杀死这个进程后,重启jenkins就可以了

官方的改法

官方的改法都是在jenkins的配置页面中进行修改,我之所没这么做,是因为我jenkins连页面都打不开(因为内存溢出啦)。

maven类型项目

①全局配置:
如果你使用的是Maven2/3项目类型,你可以在jenkins全局配置中设置-Xmx or -XX:MaxPermSize。通过导航(Manage Jenkins -> Configure System),接着找到Maven Project Configuration,在Global MAVEN_OPTS这一栏中添加需要设置的jvm参数并点击保存。随后的Maven2/3 job构建将会使用新的设置。

②项目设置:
这个设置是针对每个job的。首先在job页面中点击configure按钮,接着找打Build部分并点击advanced,接着在MAVEN_OPTS这个选项中设置相关参数。

Freestyle projects with Maven Build Steps

如果你有一个自由式项目并使用Invoke Top Level Maven Targets构建步骤,你可以点击高级按钮,在JVM Options这一栏添加jvm参数。

另外,可以在jenkins全局配置,通过添加MAVEN_OPTS全局变量来影响所有自由风格maven的构建步骤。具体配置路径:先点击Manage Jenkins,接着Configure System,在Global properties这一栏中,勾选Environment Variables复选框,接着添加一个新的名为MAVEN_OPTS的环境变量,并设置一个合适的值:

未分类

Gradle build steps

这里同理上面,可以在系统设置中添加全局变量

Ant build steps

对于Ant 步骤,其没有全局环境变量,你必须在每个单独的构建步骤中设置Ant选项。在构建的设置中,找到Invoke Ant步骤,点击高级按钮,Java Options这一栏输入参数。

参考地址:
https://wiki.jenkins.io/display/JENKINS/Builds+failing+with+OutOfMemoryErrors