大型网站tomcat服务器管理全集6.md

Tomcat 运维实战

1、JVM 虚拟机常识

两个常识问题

作为了解JVM 虚拟机的开始。我们很有必要弄明白以下两个问题。

1、什么是JAVA虚拟机

所谓虚拟机,就是一台虚拟的计算机。他是一款软件,用来执行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机。大名鼎鼎的VisualBox、VMware就属于系统虚拟机。他们完全是对物理计算机的仿真。提供了一个可以运行完整操作系统的软件平台。
程序虚拟机的典型代表就是Java虚拟机,它专门为执行单个计算机程序而设计,在Java虚拟机中执行的指令我们称为Java字节码指令。无论是系统虚拟机还是程序虚拟机,在上面运行的软件都呗限制于虚拟机提供的资源中。

2、JAVA 如何做到跨平台

在这里插入图片描述

同一个JAVA程序(JAVA字节码的集合),通过JAVA虚拟机(JVM)运行于各大主流操作系统平台
比如Windows、CentOS、Ubuntu等。程序以虚拟机为中介,来实现跨平台。

3、虚拟机基本结构

我们要对JVM虚拟机的结构有一个感性的认知。毕竟我们不是编程人员,认知程度达不到那么深入。

在这里插入图片描述

1、类加载子系统
负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间。除了类信息外,方法区中可能还会存放运行时常量池信息,包括字符串字面量和数字量。

2、Java堆
在虚拟机启动的时候建立,它是Java程序最主要的内存工作区域。几乎所有的Java对象实例都放Java堆中。堆空间是所有线程共享的,这是一块与Java应用密切相关的内存区间。

3、Java的NIO库(直接内存)
允许Java程序使用直接内存。直接内存是在Java堆外的、直接向系统申请的内存区间。通常访问直接内存的速度会优于Java堆。因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。由于直接内存在Java堆外,因此它的大小不会受限于Xmx指定的最大堆大小。但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存。

4、垃圾回收系统
垃圾回收系统是Java虚拟机的重要组成部分,垃圾回收器可以对方法区、Java堆和直接内存进行回收。

5、Java栈
每一个Java虚拟机线程都有一个私有的Java栈。一个线程的Java栈在线程创建的时候被创建。Java保存着帧信息,Java栈中保存着局部变量、方法参数,同时和Java方法的调用、返回密切相关。

6、本地方法
与Java栈非常类似,最大的不同在于Java栈用于Java方法的调用,而本地方法栈用于本地方法调用。作为Java虚拟机的重要扩展,Java虚拟机运行Java程序直接调用本地方法(通常使用C编写)。

7、PC寄存器
每个线程私有的空间,Java虚拟机会为每一个Java线程创建PC寄存器。在任意时刻,一个Java线程总是在执行一个方法,这个正在被执行的方法称为当前方法。如果当前方法不是本地方法,PC寄存器就会指向当前正在被执行的指令。如果当前方法是本地方法,那么PC寄存的值就是undefined.

8、执行引擎
是Java虚拟机最核心组件之一,它负责执行虚拟机的字节码。现代虚拟机为了提高执行效率。会使用即时编译技术将方法编译成机器码后再执行。

4、虚拟机堆内存结构

在这里插入图片描述

JVM中堆空间可以分成三个大区,年轻代、老年代、永久代(方法区)。

1、年轻代
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分为三个区域:EDEN、Survivor0(简称S0,也通常称为from区)、Survivor1(简称S1,也通常称为to区)。其中S0与S1的大小是相同等大的,三者所占年轻代的比例大致为8:1:1,S0与S1就像"孪生兄弟"一样,我们大家不必去纠结此比例(可以通过修改JVM某些动态参数来调整)的大小.只需谨记三点就好:
1.S0与S1相同大小。
2.EDEN区远比S(S0+S1)区大,EDEN占了整个年轻代的大致70%至80%左右。 
3.年轻代分为2个区(EDEN区、Survivor区)、3个板块(EDEN、S0、S1)。
2、老年代
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
那一个对象到底要经过多少次垃圾回收才能从年轻代进入老年代呢?
我们通常认为在新生代中的对象,每经历过一次GC,如果它没有被回收,它的年龄就会被加1, 虚拟机提供了一个参数来可控制新生代对象的最大年龄:MaxTenuringThreshold。默认情况下,这个参数是15。 也就是说,在新生代的对象最多经历15次GC,就可以进入老年代。
假如存在一种这样的情况,一个新生代对象,占用新生代空间特别大。在GC时若不回收,新生代空间将不足。但是若要回收,程序还没有使用完。此时就不会依据这个对象的 MaxTenuringThreshold 参数。而是直接晋升到老年代。所以说
MaxTenuringThreshold 参数是晋升老年代的充分非必要条件。
3、永久代(方法区)
也通常被叫做方法区。是一块所有线程共享的内存区域。用于保存系统的类信息,比如类的字段、方法、常量池。

5、常用虚拟机参数

JVM 虚拟机提供了三种类型参数

1、标准参数
标准参数中包括功能和输出的参数都是很稳定的,很可能在将来的JVM版本中不会改变。你可以用 java 命令(或者是用 java -help)检索出所有标准参数。
2、X 类型参数
非标准化的参数,在将来的版本中可能会改变。所有的这类参数都以 -X 开始,并且可以用 java -X 来检索。
注意,不能保证所有参数都可以被检索出来,其中就没有 -Xcomp 。
3、XX 类型参数
非标准化的参数(到目前为止最多的),它们同样不是标准的,甚至很长一段时间内不被列出来。然而,在实际情况中 X 参数和 XX 参数并没有什么不同。X 参数的功能是十分稳定的,然而很多 XX 参数仍在实验当中(主要是 JVM 的开发者用于 debugging 和调优 JVM 自身的实现)。

用一句话来说明 XX 参数的语法。所有的 XX 参数都以"-XX:"开始,但是随后的语法不同,取决于参数的类型:
1)对于布尔类型的参数,我们有"+"或"-",然后才设置 JVM 选项的实际名称。
   例如,-XX:+ 用于激活选项,而 -XX:- 用于注销选项。
   Example:
   开启GC日志的参数: -XX:+PrintGC
2) 对于需要非布尔值的参数,如 string 或者 integer,我们先写参数的名称,后面加上"=",最后赋值。
   例如: -XX:MaxPermSize=2048m

6、常用的JVM参数

以上介绍完了JVM的三类参数类型,接下来我们主要聊聊常用的JVM参数。

1、跟踪JAVA虚拟机的垃圾回收

JVM 的 GC的日志是以替换的方式(>)写入的,而不是追加(>>),如果下次写入到同一个文件中的话,以前的GC内容会被清空。这导致我们重启了JAVA服务后,历史的GC日志将会丢失。

-XX:+PrintGC 
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename

Example

此种写法,会导致JAVA服务重启后,GC日志丢失

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/data0/logs/gc.log

在这里GC 日志支持 %p 和 %t 两个参数:

  • %p 将会被替换为对应的进程PID
  • %t 将会被替代为时间字符串,格式为: YYYY-MM-DD_HH-MM-SS

此种写法,不管怎么重启,GC历史日志将不会丢失

-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data0/logs/gc-%t.log"
2、配置JAVA虚拟机的堆空间
-Xms:初始堆大小
-Xmx:最大堆大小
实际生产环境中, 我们通常将初四化堆(-Xms) 和 最大堆(-Xmx) 设置为一样大。以避免程序频繁的申请堆空间。

-Xmn: 设置年轻代大小
-XX:NewRatio=老年代/新生代 //设置年轻代和年老代的比值
-XX:SurvivorRatio=eden/from=eden/to //年轻代中Eden区与两个Survivor区的比值

Example:

-Xmn1m -XX:SurvivorRatio=2
// 这里的eden 于from(to) 的比值为2:1 ,因此在新生代为1m的区间里, eden 区为 512KB, from 和 to 分别为 256KB. 而新生代总大小为 512KB + 256KB + 256KB = 1MB
-Xms20M -Xmx20M -XX:NewRatio=2
// 这里 老年代和新生代的比值为2:1 , 因此在堆大小为20MB的区间里, 新生代大小为: 20MB * 1/3 = 6MB左右
// 老年代为 13MB 左右。
3、配置JAVA虚拟机的永久区(方法区)
-XX:PermSize=n    //设置初始化值
-XX:MaxPermSize=n //设置持久代大小
4、配置JAVA虚拟机的栈
-Xss128k 设置每个线程的堆栈大小

7、常用垃圾回收算法

1、引用计数法
引用计数法是最经典的一种垃圾回收算法。其实现很简单,对于一个A对象,只要有任何一个对象引用了A,则A的引用计算器就加1,当引用失效时,引用计数器减1.只要A的引用计数器值为0,则对象A就不可能再被使用。
       
虽然其思想实现都很简单(为每一个对象配备一个整型的计数器),但是该算法却存在两个严重的问题:
1)无法处理循环引用的问题,因此在Java的垃圾回收器中,没有使用该算法。
2)引用计数器要求在每次因引用产生和消除的时候,需要伴随一个加法操作和减法操作,对系统性能会有一定的影响。

一个简单的循环引用问题描述:
对象A和对象B,对象A中含有对象B的引用,对象B中含有对象A的引用。此时对象A和B的引用计数器都不为0,但是系统中却不存在任何第三个对象引用A和B。也就是说A和B是应该被回收的垃圾对象,但由于垃圾对象间的互相引用使得垃圾回收器无法识别,从而引起内存泄漏(由于某种原因不能回收垃圾对象占用的内存空间)。

如下图:不可达对象出现循环引用,它的引用计数器不为0

在这里插入图片描述

注意:由于引用计数器算法存在循环引用以及性能的问题,java虚拟机并未使用此算法作为垃圾回收算法。
【可达对象】通过根对象的进行引用搜索,最终可以到达的对象。
【不可达对象】通过根对象进行引用搜索,最终没有被引用到的对象。
2、标记清除法
标记-清除算法是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。
缺陷:
①.效率问题:标记清除过程效率都不高。 
②.空间问题:标记清除之后会产生大量的不连续的内存碎片

在这里插入图片描述

3、 标记压缩法
标记-压缩算法适合用于存活对象较多的场合,如老年代。它在标记-清除算法的基础上做了一些优化。和标记-清除算法一样,标记-压缩算法也首先需要从根节点开始,对所有可达对象做一次标记。但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端。之后,清理边界外所有的空间。
标记-压缩算法的最终效果等同于标记-清除算法执行完成之后,再进行一次内存碎片的整理。基于此,这种算法也解决了内存碎片问题。

在这里插入图片描述

4、复制算法
与标记-清除算法相比,复制算法是一种相对高效的回收方法。但不适用于存活对象较多的场合,如老年代。它将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收
缺陷: 
空间浪费,浪费了50%的内存空间。

在这里插入图片描述

我们前文介绍的JVM 的新生代,分为Eden 及 S0 和 S1 , 其中S0 和 S1 是两个容量相等的区域。其实在JVM 的垃圾回收中, S0 和 S1 就使用了复制算法作为它们的垃圾回收算法。
# 使用JDK 自带的jmap 工具,打印一个JVM 虚拟机的堆信息. 
# 其中 187136 为JVM 的PID

[root@java00 ~]# jmap -heap 187136
Attaching to process ID 187136, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.80-b11

using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 4294967296 (4096.0MB)
   NewSize          = 1431633920 (1365.3125MB)
   MaxNewSize       = 1431633920 (1365.3125MB)
   OldSize          = 2863267840 (2730.625MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 1073741824 (1024.0MB)
   MaxPermSize      = 2147483648 (2048.0MB)
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 1288503296 (1228.8125MB)
   used     = 570069688 (543.6608200073242MB)
   free     = 718433608 (685.1516799926758MB)
   44.242780734027704% used
Eden Space:
   capacity = 1145372672 (1092.3125MB)
   used     = 561190696 (535.1931533813477MB)
   free     = 584181976 (557.1193466186523MB)
   48.99634064256773% used
From Space:
   capacity = 143130624 (136.5MB)
   used     = 8878992 (8.467666625976562MB)
   free     = 134251632 (128.03233337402344MB)
   6.2034187736092035% used
To Space:
   capacity = 143130624 (136.5MB)
   used     = 0 (0.0MB)
   free     = 143130624 (136.5MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 2863333376 (2730.6875MB)
   used     = 46529976 (44.37444305419922MB)
   free     = 2816803400 (2686.313056945801MB)
   1.6250282412102892% used
Perm Generation:
   capacity = 1073741824 (1024.0MB)
   used     = 47940496 (45.71961975097656MB)
   free     = 1025801328 (978.2803802490234MB)
   4.464806616306305% used

20796 interned Strings occupying 2411488 bytes.
# 截取部分信息如下: From(S0) 和 To(S1) 区间采用了复制算法,不论什么时候执行jmap 区间,都会发现
# 有一个区间的使用用于都是 0.0% used
From Space:
   capacity = 143130624 (136.5MB)
   used     = 8878992 (8.467666625976562MB)
   free     = 134251632 (128.03233337402344MB)
   6.2034187736092035% used
To Space:
   capacity = 143130624 (136.5MB)
   used     = 0 (0.0MB)
   free     = 143130624 (136.5MB)
   0.0% used
5、分代算法
    前文介绍了复制、标记清除、标记压缩等垃圾回收算法。在所有的算法中,并没有一种算法可以完全取代其他算法,它们都具有自己独特的优势和特点。因此,根据垃圾回收对象的特性,使用合适的算法回收,才是明智的选择。分代算法就是基于这种思想,它将内存区间根据对象的特点分成几块,根据每块内存区间的特点,使用不同的回收算法,以提高垃圾回收的效率。
    一般来说,Java虚拟机会将所有的新建对象都放到称为新生代的区域中,新生代的特点是对象朝生夕灭,大约90%的新建对象会被回收,因此新生代比较适合使用复制算法。当一个对象经过几次回收后依然存活,对象就会被放到称为老年代的内存空间。在老年代中,几乎所有对象都经过几次垃圾回收后依然得以存活的。因此可以认为对象在一段时期内,甚至在应用程序的整个生命周期中,将是常驻内存的。
    在极端情况下,老年代对象的存活率可以达到100%。如果依然使用复制算法回收老年代,将需要复制大量对象。再加上老年代的回收性价比也要低于新生代,因此这种做法是不可取的。根据分代的思想,可以对老年代的回收使用与新生代不通的标记压缩或者标记清除算法,以提高垃圾回收效率。

在这里插入图片描述

2、JVM 运维实用排障工具

1、jps

用来查看Java进程的具体状态, 包括进程ID,进程启动的路径及启动参数等等,与unix上的ps类似,只不过jps是用来显示java进程,可以把jps理解为ps的一个子集。
常用参数如下:
-q:忽略输出的类名、Jar名以及传递给main方法的参数,只输出pid
-m:输出传递给main方法的参数,如果是内嵌的JVM则输出为null
-l:输出完全的包名,应用主类名,jar的完全路径名
-v:输出传给jvm的参数

注意: 使用jps 时的运行账户要和JVM 虚拟机启动的账户一致。若启动JVM虚拟机是运行的账户为www,那使用jps指令时,也要使用www 用户去指定。 sudo -u www jps

Example

// 查看已经运行的JVM 进程的实际启动参数
[root@localhost3 bin]# jps  -v
38372 Jps -Dapplication.home=/usr/local/jdk -Xms8m
38360 Bootstrap -Djava.util.logging.config.file=/data0/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms4096m -Xmx4096m -XX:PermSize=1024m -XX:MaxPermSize=2048m -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dignore.endorsed.dirs= -Dcatalina.base=/data0/tomcat -Dcatalina.home=/data0/tomcat -Djava.io.tmpdir=/data0/tomcat/temp

2、jstack

jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息。如果现在运行的java程序呈现hung的状态,jstack是非常有用的。此信息通常在运维的过程中被保存起来(保存故障现场),以供RD们去分析故障。
常用参数如下:
jstack <pid>
jstack [-l] <pid> //长列表. 打印关于锁的附加信息
jstack [-F] <pid> //当’jstack [-l] pid’没有响应的时候强制打印栈信息

Example

// 打印JVM 的堆栈信息,以供问题排查
[root@localhost3 ~]# jstack -F 38360 > /tmp/jstack.log

3、jinfo

可以查看或修改运行时的JVM进程的参数。
常用参数:
jinfo [option] pid
    
where <option> is one of:
    -flag <name>         to print the value of the named VM flag
    -flag [+|-]<name>    to enable or disable the named VM flag
    -flag <name>=<value> to set the named VM flag to the given value
    -flags               to print VM flags

Example

// 根据 PID 查看目前分配的最大堆栈
[root@localhost3 ~]# jinfo -flag MaxHeapSize 38360
-XX:MaxHeapSize=4294967296
// 动态更改 JVM 的最大堆栈值
[root@localhost3 ~]# jinfo -flag MaxHeapSize=4294967296  38360
Exception in thread "main" com.sun.tools.attach.AttachOperationFailedException: flag 'MaxHeapSize' cannot be changed

	at sun.tools.attach.LinuxVirtualMachine.execute(LinuxVirtualMachine.java:229)
	at sun.tools.attach.HotSpotVirtualMachine.executeCommand(HotSpotVirtualMachine.java:261)
	at sun.tools.attach.HotSpotVirtualMachine.setFlag(HotSpotVirtualMachine.java:234)
	at sun.tools.jinfo.JInfo.flag(JInfo.java:134)
	at sun.tools.jinfo.JInfo.main(JInfo.java:81)

// jinfo 并不能动态的改变所有的JVM 参数。 那到底有哪些参数能够被动态的改变呢?
// java -XX:+PrintFlagsFinal -version 答应JVM 的所有参数
// java -XX:+PrintFlagsFinal -version | grep manageable

[root@localhost3 ~]# java -XX:+PrintFlagsFinal -version | grep manageable
     intx CMSAbortablePrecleanWaitMillis            = 100                                 {manageable}
     intx CMSTriggerInterval                        = -1                                  {manageable}
     intx CMSWaitDuration                           = 2000                                {manageable}
     bool HeapDumpAfterFullGC                       = false                               {manageable}
     bool HeapDumpBeforeFullGC                      = false                               {manageable}
     bool HeapDumpOnOutOfMemoryError                = false                               {manageable}
    ccstr HeapDumpPath                              =                                     {manageable}
    uintx MaxHeapFreeRatio                          = 70                                  {manageable}
    uintx MinHeapFreeRatio                          = 40                                  {manageable}
     bool PrintClassHistogram                       = false                               {manageable}
     bool PrintClassHistogramAfterFullGC            = false                               {manageable}
     bool PrintClassHistogramBeforeFullGC           = false                               {manageable}
     bool PrintConcurrentLocks                      = false                               {manageable}
     bool PrintGC                                   = false                               {manageable}
     bool PrintGCDateStamps                         = false                               {manageable}
     bool PrintGCDetails                            = false                               {manageable}
     bool PrintGCID                                 = false                               {manageable}
     bool PrintGCTimeStamps                         = false                               {manageable}
     
// 也只有以上这些值才能够动态的被改变
[root@localhost3 ~]# jinfo -flag CMSWaitDuration=1900  38360
# 查看, jinfo -flags 查看 JVM 的 flags 
[root@localhost3 ~]# jinfo -flags 38360
Attaching to process ID 38360, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.91-b14
Non-default VM flags: -XX:CICompilerCount=2 -XX:CMSWaitDuration=1900 -XX:InitialHeapSize=4294967296 -XX:MaxHeapSize=4294967296 -XX:MaxNewSize=1431633920 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=1431633920 -XX:OldSize=2863333376 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps
Command line:  -Djava.util.logging.config.file=/data0/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms4096m -Xmx4096m -XX:PermSize=1024m -XX:MaxPermSize=2048m -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dignore.endorsed.dirs= -Dcatalina.base=/data0/tomcat -Dcatalina.home=/data0/tomcat -Djava.io.tmpdir=/data0/tomcat/temp

4、jstat

// 监控JVM 的状态,常用指令:
# jstat -gc 113059 1000 10 // 打印PID 为 113059 JVM 状态,一共打印10次,每次间隔时间为1s(1000ms)
// 注 jstat 的用法超级强大, 我们这里只是列举出列其中一个简单的应用。

Example

# jstat -gc 113059 1000 10
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT
195904.0 195904.0  0.0   21610.3 1567680.0 1516721.9 8526272.0  3557507.8  1048576.0 163148.4   2577   92.033   0      0.000   92.033
195904.0 195904.0 23600.9  0.0   1567680.0 142541.6 8526272.0  3558435.8  1048576.0 163148.4   2578   92.060   0      0.000   92.060
195904.0 195904.0 23600.9  0.0   1567680.0 266338.1 8526272.0  3558435.8  1048576.0 163148.4   2578   92.060   0      0.000   92.060
195904.0 195904.0 23600.9  0.0   1567680.0 413941.8 8526272.0  3558435.8  1048576.0 163148.4   2578   92.060   0      0.000   92.060
195904.0 195904.0 23600.9  0.0   1567680.0 642390.6 8526272.0  3558435.8  1048576.0 163148.4   2578   92.060   0      0.000   92.060
195904.0 195904.0 23600.9  0.0   1567680.0 813957.3 8526272.0  3558435.8  1048576.0 163148.4   2578   92.060   0      0.000   92.060
195904.0 195904.0 23600.9  0.0   1567680.0 984223.2 8526272.0  3558435.8  1048576.0 163148.4   2578   92.060   0      0.000   92.060
195904.0 195904.0 23600.9  0.0   1567680.0 1155472.7 8526272.0  3558435.8  1048576.0 163148.4   2578   92.060   0      0.000   92.060
195904.0 195904.0 23600.9  0.0   1567680.0 1399228.5 8526272.0  3558435.8  1048576.0 163148.4   2578   92.060   0      0.000   92.060
195904.0 195904.0  0.0   23866.6 1567680.0 38005.6  8526272.0  3559196.7  1048576.0 163148.4   2579   92.092   0      0.000   92.092

字段意义如下

列名 说明
S0C 新生代中Survivor space中S0当前容量的大小(KB)
S1C 新生代中Survivor space中S1当前容量的大小(KB)
S0U 新生代中Survivor space中S0容量使用的大小(KB)
S1U 新生代中Survivor space中S1容量使用的大小(KB)
EC Eden space当前容量的大小(KB)
EU Eden space容量使用的大小(KB)
OC Old space当前容量的大小(KB)
OU Old space使用容量的大小(KB)
PC Permanent space当前容量的大小(KB)
PU Permanent space使用容量的大小(KB)
YGC 从应用程序启动到采样时发生 Young GC 的次数
YGCT 从应用程序启动到采样时 Young GC 所用的时间(秒)
FGC 从应用程序启动到采样时发生 Full GC 的次数
FGCT 从应用程序启动到采样时 Full GC 所用的时间(秒)
GCT T从应用程序启动到采样时用于垃圾回收的总时间(单位秒),它的值等于YGC+FGC

5、jvmtop

以上介绍的jps、jstack、jinfo等都是安装JDK 时自带的系统分析工具,而jvmtop是一款开源的JVM工具。
它的下载地址如下: https://github.com/patric-r/jvmtop
顾名思义,它是一个只针对JVM的工具,展示的方式和unix的top命令相似.
jvmtop 提供了两个视图,一个是概览视图,可以展示出当前机器的所有的 JVM 的情况. 还有一个视图是详情视图,展示一个 JVM 的详细情况.

概览视图

jvmtop.sh
其中,各个字段的意义分别如下:
PID:进程 ID
MAIN-CLASS:main 类的名字
HPCUR:当前被使用的 heap 的大小
HPMAX:最大可用的 heap 的大小
NHCUR:当前被使用的非 heap 大小(比如:perm gen)
NHMAX:最大可用的非 heap 大小
CPU:CPU 的使用情况
GC:消耗在 GC 上的时间比例
VM:JVM 的提供者,大版本号,小版本号,图中的意思是 Apple 提供的 JDK 6U51 版本。
USERNAME:当前的用户名
#T:线程数量
DL:是否有现成发生死锁

详情视图

jvmtop.sh <pid>

在这里插入图片描述

其中,各个字段的意义如下:
TID:线程 ID
NAME:线程名
STATE:线程状态
CPU:线程当前的 CPU 占用情况
TOTALCPU:从线程被创建开始总体的 CPU 占用情况
BLOCKBY:阻塞这个线程的线程 ID

3、JVM 运维实用监控工具

1、VirtualVM

VisualVM 是一款免费的性能分析工具。它通过 jvmstat、JMX、SA(Serviceability Agent)以及 Attach API 等多种方式从程序运行时获得实时数据,从而进行动态的性能分析。同时,它能自动选择更快更轻量级的技术尽量减少性能分析对应用程序造成的影响,提高性能分析的精度。
1、安装 VisualVM
到官网下载相应操作系统对应的软件.
官网地址: http://visualvm.github.io/
2、安装 VisualVM插件
VisualVM 插件中心提供很多插件以供安装。可以通过 VisualVM 应用程序安装,或者从 VisualVM 插件中心手动下载插件,然后离线安装。
    
    从 VisualVM 插件中心安装插件步骤:
    * 从主菜单中选择“工具”>“插件”。
    * 在“可用插件”标签中,选中该插件的“安装”复选框。单击”安装“。
    * 逐步完成插件安装程序。
    
    离线安装插件步骤:
    * 到插件中心官网: http://visualvm.github.io/pluginscenters.html 下周对应的VisualVM版本的插件
    * 从主菜单中选择“工具”>“插件”。
    * 在“已下载”标签中,点击"添加插件"按钮,选择已下载的插件文件 (以.nbm结尾) 打开。
    * 选中要打开的插件文件,并单击"安装"按钮,逐步完成插件安装程序。
3、如何监控JVM
那如何通过VisualVM 去分析远程的JVM虚拟机里的信息呢?
首先要在JVM中开启相关配置,以供VisualVM能够从中获取JVM的信息,如何配置JVM呢? 这里以Tomcat为例:

在Tomcat的 catalina.sh 或者是setenv.sh 脚本中加上如下参数
 -Dcom.sun.management.jmxremote 
 -Dcom.sun.management.jmxremote.port=一个监听端口 
 -Dcom.sun.management.jmxremote.authenticate=false 
 -Dcom.sun.management.jmxremote.ssl=false 
 -Djava.rmi.server.hostname=可解析的主机名称

具体测试参数如下:
 -Dcom.sun.management.jmxremote 
 -Dcom.sun.management.jmxremote.port=11412 
 -Dcom.sun.management.jmxremote.authenticate=false 
 -Dcom.sun.management.jmxremote.ssl=false 
 -Djava.rmi.server.hostname=java01.xulei.com

 注意这里的java01.xulei.com 必须是DNS可解析的主机名,11412 为监听端口

 其次在VisualVM 中配置连接到上面配置的服务器加端口的地址上去:
 * 在VisualVM中选择"远程"
 * 在弹出的窗口中选择"添加远程主机"
 * 此时会在远程中,多出一台主机。此时点击多出来的主机
 * 添加连接JVM相关的信息

VisualVM如何监控JVM具体操作截图

应用程序中找到: 远程

添加远程主机:主机名/域名

观察应用程序中:远程 显示添加的新主机

添加JMX连接 输入域名:11412 (勾选不要求ssl)

2、JmxTrans

JmxTrans 是一个可以实时通过JMX查询JVM 虚拟机状态的工具,它可以将通过JMX查询到的信息实时的录入到Ganglia、Graphite、Zabbix 等。

在这里插入图片描述

1、安装JmxTrans
// 下载 RPM 包,下载地址: http://central.maven.org/maven2/org/jmxtrans/jmxtrans/
// 这里下载的RPM包为: http://central.maven.org/maven2/org/jmxtrans/jmxtrans/266/jmxtrans-266.rpm
# yum -y install java // 由于jmxtrans 打包的原因,安全前必须依赖java软件包。所以安装。
# rpm -ivh jmxtrans-266.rpm // 若无法正常运行,可以试试其他版本
// 安装完成后,
// 有关 jmxtrans 程序安装在 /usr/share/jmxtrans 目录中
// 有关 jmxtrans 程序的启动脚本 /etc/init.d/jmxtrans
// 有关 jmxtrans 程序抓取JMX 的配置存放在 /var/lib/jmxtrans, 且是json文件的格式
// 有关 jmxtrans 程序的配置文件 /etc/jmxtrans/wrapper.conf
// 有关 jmxtrans 程序启动是的错误信息存储在 /var/log/jmxtrans/jmxtrans.log 
2、使用JmxTrans 采集数据

在 /var/lib/jmxtrans 目录下,创建 test.json 文件。 软后重启 jmxtrans 服务。

由于是测试,我们将收集到的JVM 信息保存到了本地的/tmp/output.txt 文件中

{
  "servers": [
    {
      "numQueryThreads": 3,
      "host": "10.200.16.228", //换成JVM 所在的服务器
      "port": 11415,       // 换成JMX 端口
      "queries": [
        {
          "outputWriters": [
            {
              "@class" : "com.googlecode.jmxtrans.model.output.KeyOutWriter",
              "outputFile" : "/tmp/output.txt"
            }
          ],
          "resultAlias": "heap",
          "obj": "java.lang:type=Memory",
          "attr": [
            "HeapMemoryUsage",
            "NonHeapMemoryUsage"
          ]
        },
        {
          "outputWriters": [
            {
              "@class" : "com.googlecode.jmxtrans.model.output.KeyOutWriter",
              "outputFile" : "/tmp/output.txt"
           }
          ],
          "resultAlias": "thread",
          "obj": "java.lang:type=Threading",
          "attr": [
            "ThreadCount",
            "PeakThreadCount",
            "DaemonThreadCount",
            "CurrentThreadCpuTime",
            "CurrentThreadUserTime",
            "TotalStartedThreadCount"
          ]
        },
        {
          "outputWriters": [
            {
              "@class" : "com.googlecode.jmxtrans.model.output.KeyOutWriter",
              "outputFile" : "/tmp/output.txt"
            }
          ],
          "resultAlias": "operatingsystem",
          "obj": "java.lang:type=OperatingSystem",
          "attr": [
            "ProcessCpuTime",
            "ProcessCpuLoad",
            "SystemCpuLoad",
            "SystemLoadAverage",
            "FreeSwapSpaceSize",
            "TotalSwapSpaceSize",
            "TotalPhysicalMemorySize",
            "CommittedVirtualMemorySize",
            "OpenFileDescriptorCount",
            "AvailableProcessors",
            "MaxFileDescriptorCount",
            "FreePhysicalMemorySize"
          ]
        }
      ]
    }
  ]
}

参考输出结果:

[root@localhost3 jmxtrans]# cat /tmp/output.txt
10_200_16_228_11415.thread.ThreadCount	418	1518065577329
10_200_16_228_11415.thread.PeakThreadCount	445	1518065577329
10_200_16_228_11415.thread.DaemonThreadCount	417	1518065577329
10_200_16_228_11415.thread.CurrentThreadCpuTime	4065386	1518065577329
10_200_16_228_11415.thread.CurrentThreadUserTime	0	1518065577329
10_200_16_228_11415.thread.TotalStartedThreadCount	53766	1518065577329
10_200_16_228_11415.heap.HeapMemoryUsage_init	4294967296	1518065577343
10_200_16_228_11415.heap.HeapMemoryUsage_committed	4151836672	1518065577343
10_200_16_228_11415.heap.HeapMemoryUsage_max	4151836672	1518065577343
10_200_16_228_11415.heap.HeapMemoryUsage_used	1066173744	1518065577343
10_200_16_228_11415.heap.NonHeapMemoryUsage_init	1076297728	1518065577343
10_200_16_228_11415.heap.NonHeapMemoryUsage_committed	1087897600	1518065577343
10_200_16_228_11415.heap.NonHeapMemoryUsage_max	2197815296	1518065577343
10_200_16_228_11415.heap.NonHeapMemoryUsage_used	99018384	1518065577343
10_200_16_228_11415.operatingsystem.ProcessCpuTime	30701230000000	1518065577381
10_200_16_228_11415.operatingsystem.ProcessCpuLoad	3.976670201484624E-4	1518065577381
10_200_16_228_11415.operatingsystem.SystemCpuLoad	0.060445387062566275	1518065577381
10_200_16_228_11415.operatingsystem.SystemLoadAverage	2.06	1518065577381
10_200_16_228_11415.operatingsystem.FreeSwapSpaceSize	6357475328	1518065577381
10_200_16_228_11415.operatingsystem.TotalSwapSpaceSize	8565813248	1518065577381
10_200_16_228_11415.operatingsystem.TotalPhysicalMemorySize	67266252800	1518065577381
10_200_16_228_11415.operatingsystem.CommittedVirtualMemorySize	25674649600	1518065577381
10_200_16_228_11415.operatingsystem.OpenFileDescriptorCount	1102	1518065577381
10_200_16_228_11415.operatingsystem.AvailableProcessors	32	1518065577381
10_200_16_228_11415.operatingsystem.MaxFileDescriptorCount	65535	1518065577381
10_200_16_228_11415.operatingsystem.FreePhysicalMemorySize	700805120	1518065577381
3、JmxTrans 的配置json 文件是怎么写出来的

这里就要结合上一节提到的 VirtualVM + MBeans 插件了,我们所有通过JmxTrans 获取到的JVM 里的信息,

在 JVM 里被叫做Mbeans。这里我们以获取堆栈和非堆栈信息来举例

        {
          "outputWriters": [
            {
              "@class" : "com.googlecode.jmxtrans.model.output.KeyOutWriter",
              "outputFile" : "/tmp/output.txt"
            }
          ],
          "resultAlias": "heap",
          "obj": "java.lang:type=Memory",
          "attr": [
            "HeapMemoryUsage",
            "NonHeapMemoryUsage"
          ]
        }
          "outputWriters": [
            {
              "@class" : "com.googlecode.jmxtrans.model.output.KeyOutWriter",
              "outputFile" : "/tmp/output.txt"
            }
          ]
//这部分信息标示,采集到的信息存储到哪里,我们这里存储到了本地文件 /tmp/output.txt 中
"resultAlias": "heap",
// 给采集到的堆栈信息和非堆栈信息加了一个类似metric 的前缀,所以我们在输出文件中看到了一下这些内容
10_200_16_228_11415.heap.HeapMemoryUsage_init	4294967296	1518065577343
10_200_16_228_11415.heap.HeapMemoryUsage_committed	4151836672	1518065577343
10_200_16_228_11415.heap.HeapMemoryUsage_max	4151836672	1518065577343
10_200_16_228_11415.heap.HeapMemoryUsage_used	1066173744	1518065577343
10_200_16_228_11415.heap.NonHeapMemoryUsage_init	1076297728	1518065577343
10_200_16_228_11415.heap.NonHeapMemoryUsage_committed	1087897600	1518065577343
10_200_16_228_11415.heap.NonHeapMemoryUsage_max	2197815296	1518065577343
10_200_16_228_11415.heap.NonHeapMemoryUsage_used	99018384	1518065577343
"obj": "java.lang:type=Memory",
// 这一部分的信息获取, 就要结合 VirtualVM + MBeans 了。 找到ObjName ,将里面的Value 原样复制过来就好
// 这是来告诉 JmxTrans 收集 Memory 信息,那到底收集内存里的一些什么东西呢? 我们继续看下面的解释。

在这里插入图片描述

          "attr": [
            "HeapMemoryUsage",
            "NonHeapMemoryUsage"
          ]
// 告诉JmxTrans , 收集内存里的 HeapMemoryUsage 和  NonHeapMemoryUsage 这两个属性。那 Memory 里
// 都有啥属性,怎么去查看呢? 这里还是离不开  VirtualVM + MBeans 的帮助。同样,我们将属性名字原样粘
// 贴过来就好

在这里插入图片描述

其实 JmxTrans 的使用不是很复杂,主要是如何去表达要获取到的属性。我们这里只是列举了最基本、也是最常见的方法。要想详细的了解JmxTrans 的使用。可以学习它的官方文档: https://github.com/jmxtrans/jmxtrans/wiki

3、部署 Tomcat + Jenkins

既然Tomcat是一个WEB应用服务器,这个服务器中运行的程序是什么语言的呢? PHP、PYTHON、JAVA还是ASP等呢?
Tomcat 服务器在生产环境中主要作为JAVA程序的WEB服务器。我们这里以Tomcat + jenkins 的部署为例来运行 jenkins 服。
   1、安装JDK8、并配置JAVA_HOME 等相关信息(新版本jenkins只有jdk8支持)
   JAVA_HOME="/usr/local/jdk"
   CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
   PATH=$PATH:"$JAVA_HOME/bin"
   2、安装Tomcat,启动Tomcat 并访问http://127.0.0.1:8080(这是使用了tomcat8 做测试)
   3、下载jenkins的war包程序
      http://mirrors.shu.edu.cn/jenkins/war/2.108/jenkins.war
   4、将jenksins.war 放到解压后的tomcat 的webapps 目录中
   5、重启tomcat,并访问 http://127.0.0.1/jenkins

1、日志格式配置

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="/data0/www/logs"
               prefix="jenkins-" suffix="-access_log"
               pattern="%{X-Real-IP}i - %v %t &quot;%r&quot; - %s %b %T &quot;%{Referer}i&quot; &quot;%{User-Agent}i&quot; %a &quot;-&quot; &quot;-&quot;" >

2、JVM 参数优化

JAVA_OPTS="$JAVA_OPTS -Xms4096m -Xmx4096m -XX:PermSize=1024m -XX:MaxPermSize=2048m"

3、开启GC日志

JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data0/logs/gc-%t.log"

4、开启JMX端口便于监控

CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=10028 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false 
-Djava.rmi.server.hostname=java69-matrix.zeus.lianjia.com"

5、取消JVM 的默认DNS缓存时间

不缓存DNS记录,避免DNS解析更改后要重启JVM虚拟机

CATALINA_OPTS="$CATALINA_OPTS -Dsun.net.inetaddr.ttl=0 -Dsun.net.inetaddr.negative.ttl=0

4、企业 Tomcat 运维

1、Tomcat 简介

Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。

Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。

Tomcat和Nginx、Apache(httpd)、lighttpd等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Nginx/Apache服务器。

目前Tomcat最新版本为9.0。Java容器还有resin、weblogic等。

Tomcat****官网: http://tomcat.apache.org

1、Tomcat好帮手---JDK

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。

JDK包含了一批用于Java开发的组件,其中包括:

javac:编译器,将后缀名为.java的源代码编译成后缀名为“.class”的字节码
java:运行工具,运行.class的字节码
jar:打包工具,将相关的类文件打包成一个文件
javadoc:文档生成器,从源码注释中提取文档,注释需匹配规范
jdb debugger:调试工具
jps:显示当前java程序运行的进程状态
javap:反编译程序
appletviewer:运行和调试applet程序的工具,不需要使用浏览器
javah:从Java类生成C头文件和C源文件。这些文件提供了连接胶合,使Java和C代码可进行交互。
javaws:运行JNLP程序
extcheck:一个检测jar包冲突的工具
apt:注释处理工具 
jhat:java堆分析工具
jstack:栈跟踪程序
jstat:JVM检测统计工具
jstatd:jstat守护进程
jinfo:获取正在运行或崩溃的java程序配置信息
jmap:获取java进程内存映射信息
idlj:IDL-to-Java编译器。将IDL语言转化为java文件 
policytool:一个GUI的策略文件创建和管理工具
jrunscript:命令行脚本运行

JDK中还包括完整的JRE(Java Runtime Environment),Java运行环境,也被称为private runtime。包括了用于产品环境的各种库类,如基础类库rt.jar,以及给开发人员使用的补充库,如国际化与本地化的类库、IDL库等等。

JDK中还包括各种样例程序,用以展示Java API中的各部分。

JDK****下载面页:

http://www.oracle.com/technetwork/java/javase/downloads/index.html

2、安装Tomcat & JDK

安装时候选择tomcat软件版本要与程序开发使用的版本一致。jdk版本要进行与tomcat保持一致。

1、系统环境说明
[root@web03 ~]# cat /etc/redhat-release 
CentOS Linux release 7.4.1708 (Core) 
[root@web03 ~]# uname -a 
Linux web03 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
[root@web03 ~]# getenforce 
Disabled
[root@web03 ~]# systemctl status firewalld.service
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:firewalld(1)
2 、安装JDK

命令集:

tar xf jdk-8u60-linux-x64.tar.gz -C /application/
ln -s /application/jdk1.8.0_60 /application/jdk
# 设置环境变量
sed -i.ori '$a export JAVA_HOME=/application/jdk\nexport PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH\nexport CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar' /etc/profile
source /etc/profile

测试jdk是否安装成功↓

[root@web03 ~]# java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
3、安装Tomcat

命令集:

tar xf apache-tomcat-8.0.27.tar.gz -C /application/
ln -s /application/apache-tomcat-8.0.27 /application/tomcat
# 设置环境变量
echo 'export TOMCAT_HOME=/application/tomcat'>>/etc/profile
source /etc/profile
# 注意授权,统一权限
chown -R root.root /application/jdk/ /application/tomcat/

检查tomcat是否安装成功

[root@web03 ~]# /application/tomcat/bin/version.sh
Using CATALINA_BASE:   /application/tomcat
Using CATALINA_HOME:   /application/tomcat
Using CATALINA_TMPDIR: /application/tomcat/temp
Using JRE_HOME:        /application/jdk
Using CLASSPATH:       /application/tomcat/bin/bootstrap.jar:/application/tomcat/bin/tomcat-juli.jar
Server version: Apache Tomcat/8.0.27
Server built:   Sep 28 2015 08:17:25 UTC
Server number:  8.0.27.0
OS Name:        Linux
OS Version:     3.10.0-693.el7.x86_64
Architecture:   amd64
JVM Version:    1.8.0_60-b27
JVM Vendor:     Oracle Corporation

2、Tomcat目录介绍

1、tomcat主目录介绍
[root@web03 ~]# cd /application/tomcat/
[root@web03 tomcat]# tree -L 1
.
├── bin              #存放tomcat管理脚本
├── conf             # tomcat 配置文件存放目录
├── lib              # web应用调用的jar包存放路径
├── LICENSE
├── logs             # tomcat 日志存放目录,catalina.out 为主要输出日志
├── NOTICE
├── RELEASE-NOTES
├── RUNNING.txt
├── temp             # 存放临时文件
├── webapps         # web程序存放目录
└── work             # 存放编译产生的.java 与 .class文件

7 directories, 4 files
2、webapps目录介绍
[root@web03 tomcat]# cd webapps/
[root@web03 webapps]# tree -L 1
.
├── docs            # tomcat 帮助文档
├── examples       # web应用实例
├── host-manager  # 主机管理
├── manager         # 管理
└── ROOT             # 默认站点根目录

5 directories, 0 files
3、Tomcat配置文件目录介绍(conf)
[root@web03 conf]# tree -L 1
.
├── Catalina
├── catalina.policy
├── catalina.properties
├── context.xml
├── logging.properties
├── logs
├── server.xml           # tomcat 主配置文件
├── server.xml.bak
├── server.xml.bak2
├── tomcat-users.xml    # tomcat 管理用户配置文件
├── tomcat-users.xsd
└── web.xml

2 directories, 10 files
4、Tomcat的管理
#  启动程序/application/tomcat/bin/startup.sh
#  关闭程序/application/tomcat/bin/shutdown.sh

启动停止

[root@web03 ~]# /application/tomcat/bin/shutdown.sh 
Using CATALINA_BASE:   /application/tomcat
Using CATALINA_HOME:   /application/tomcat
Using CATALINA_TMPDIR: /application/tomcat/temp
Using JRE_HOME:        /application/jdk
Using CLASSPATH:       /application/tomcat/bin/bootstrap.jar:/application/tomcat/bin/tomcat-juli.jar
[root@web03 ~]# /application/tomcat/bin/startup.sh 
Using CATALINA_BASE:   /application/tomcat
Using CATALINA_HOME:   /application/tomcat
Using CATALINA_TMPDIR: /application/tomcat/temp
Using JRE_HOME:        /application/jdk
Using CLASSPATH:       /application/tomcat/bin/bootstrap.jar:/application/tomcat/bin/tomcat-juli.jar
Tomcat started.

​ 注意:tomcat未启动的情况下使用shutdown脚本,会有大量的输出信息。

检查tomcat是否启动正常

[root@web03 ~]# netstat -lntup  |grep java
tcp6       0      0 :::8080         :::*                   LISTEN      30560/java          
tcp6       0      0 127.0.0.1:8005          :::*          LISTEN      30560/java          
tcp6       0      0 :::8009                 :::*           LISTEN      30560/java      

说明:所有与java相关的,服务启动都是java命名的进程

启动完成浏览器进行访问

http://10.0.0.17:8080/

3、Tomcat日志说明

查看日志
[root@web03 ~]# tailf /application/tomcat/logs/catalina.out
24-Nov-2017 15:09:51.654 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
24-Nov-2017 15:09:51.665 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
24-Nov-2017 15:09:51.670 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 60037 ms

​ 发现启动时间较长,其中有一项的启动时间占据了绝大多数

24-Nov-2017 15:09:50.629 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive /application/apache-tomcat-8.0.27/webapps/memtest.war has finished in 58,892 ms

​ 发现耗时在这里:是session引起的随机数问题导致的。Tocmat的Session ID是通过SHA1算法计算得到的,计算Session ID的时候必须有一个密钥。为了提高安全性Tomcat在启动的时候会通过随机生成一个密钥。

4、解决Tomcat启动慢的方法

Tomcat启动慢主要原因是生成随机数的时候卡住了,导致tomcat启动不了。

是否有足够的熵来用于产生随机数,可以通过如下命令来查看

[root@web03 ~]# cat /proc/sys/kernel/random/entropy_avail
6

为了加速/dev/random提供随机数的速度,你可以通过操作设备的外设,让其产生大量的中断,网络传输数据,按键,移动鼠标,在命令行敲几个不同的命令,俗称聚气。

cat /dev/random 会消耗能量

方法1****:

vim $JAVA_HOME/jre/lib/security/java.security
securerandom.source=file:/dev/random

改为

securerandom.source=file:/dev/urandom

方法2****:

vim $TOMCAT_HOME/bin/catalina.sh
if [[ "$JAVA_OPTS" != *-Djava.security.egd=* ]]; then
    JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/urandom"
fi

这个系统属性egd表示熵收集守护进程(entropy gathering daemon)

方法3****:(推荐)

yum install rng-tools # 安装rngd服务(熵服务,增大熵池)
systemctl start rngd  # 启动服务

5、Tomcat主配置文件详解

1、server.xml组件类别

顶级组件:位于整个配置的顶层,如server。

容器类组件:可以包含其它组件的组件,如service、engine、host、context。

连接器组件:连接用户请求至tomcat,如connector。

被嵌套类组件:位于一个容器当中,不能包含其他组件,如Valve、logger。

<server>
     <service>
     <connector />
     <engine>
     <host>
     <context></context>
     </host>
     <host>
     <context></context>
     </host>
     </engine>
     </service>
</server>
2、组件介绍
组件名称 功能介绍
engine 核心容器组件,catalina引擎,负责通过connector接收用户请求,并处理请求,将请求转至对应的虚拟主机host。
host 类似于httpd中的虚拟主机,一般而言支持基于FQDN的虚拟主机。
context 定义一个应用程序,是一个最内层的容器类组件(不能再嵌套)。配置context的主要目的指定对应对的webapp的根目录,类似于httpd的alias,其还能为webapp指定额外的属性,如部署方式等。
connector 接收用户请求,类似于httpd的listen配置监听端口的。
service****(服务) 将connector关联至engine,因此一个service内部可以有多个connector,但只能有一个引擎engine。service内部有两个connector,一个engine。因此,一般情况下一个server内部只有一个service,一个service内部只有一个engine,但一个service内部可以有多个connector。
server 表示一个运行于JVM中的tomcat实例。
Valve 阀门,拦截请求并在将其转至对应的webapp前进行某种处理操作,可以用于任何容器中,比如记录日志(access log valve)、基于IP做访问控制(remote address filter valve)。
logger 日志记录器,用于记录组件内部的状态信息,可以用于除context外的任何容器中。
realm 可以用于任意容器类的组件中,关联一个用户认证库,实现认证和授权。可以关联的认证库有两种:UserDatabaseRealm、MemoryRealm和JDBCRealm。
UserDatabaseRealm 使用JNDI自定义的用户认证库。
MemoryRealm 认证信息定义在tomcat-users.xml中。
JDBCRealm 认证信息定义在数据库中,并通过JDBC连接至数据库中查找认证用户。
3、server.xml配置文件注释
<?xml version='1.0' encoding='utf-8'?>
<!--
<Server>元素代表整个容器,是Tomcat实例的顶层元素.由org.apache.catalina.Server接口来定义.它包含一个<Service>元素.并且它不能做为任何元素的子元素.
    port指定Tomcat监听shutdown命令端口.终止服务器运行时,必须在Tomcat服务器所在的机器上发出shutdown命令.该属性是必须的.
    shutdown指定终止Tomcat服务器运行时,发给Tomcat服务器的shutdown监听端口的字符串.该属性必须设置
-->
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>
  <!--service服务组件-->
  <Service name="Catalina">
    <!-- Connector主要参数说明(见下表) -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    <!--engine,核心容器组件,catalina引擎,负责通过connector接收用户请求,并处理请求,将请求转至对应的虚拟主机host
        defaultHost指定缺省的处理请求的主机名,它至少与其中的一个host元素的name属性值是一样的
    -->
    <Engine name="Catalina" defaultHost="localhost">
      <!--Realm表示存放用户名,密码及role的数据库-->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <!-- 详情常见下表(host参数详解)-->
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <!-- 详情常见下表(Context参数说明 )-->
        <Context path="" docBase="" debug=""/>
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>
4、Connector主要参数说明
参数 参数说明
connector 接收用户请求,类似于httpd的listen配置监听端口.
port 指定服务器端要创建的端口号,并在这个端口监听来自客户端的请求。
address 指定连接器监听的地址,默认为所有地址(即0.0.0.0)
protocol 连接器使用的协议,支持HTTP和AJP。AJP(Apache Jserv Protocol)专用于tomcat与apache建立通信的, 在httpd反向代理用户请求至tomcat时使用(可见Nginx反向代理时不可用AJP协议)。
minProcessors 服务器启动时创建的处理请求的线程数
maxProcessors 最大可以创建的处理请求的线程数
enableLookups 如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名,若为false则不进行DNS查询,而是返回其ip地址
redirectPort 指定服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号
acceptCount 指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理
connectionTimeout 指定超时的时间数(以毫秒为单位)
5、host参数详解
参数 参数说明
host 表示一个虚拟主机
name 指定主机名
appBase 应用程序基本目录,即存放应用程序的目录.一般为appBase="webapps",相对于CATALINA_HOME而言的,也可以写绝对路径。
unpackWARs 如果为true,则tomcat会自动将WAR文件解压,否则不解压,直接从WAR文件中运行应用程序
autoDeploy 在tomcat启动时,是否自动部署。
xmlValidation 是否启动xml的校验功能,一般xmlValidation="false"。
xmlNamespaceAware 检测名称空间,一般xmlNamespaceAware="false"。
6、Context参数说明
参数 参数说明
Context 表示一个web应用程序,通常为WAR文件
docBase 应用程序的路径或者是WAR文件存放的路径,也可以使用相对路径,起始路径为此Context所属Host中appBase定义的路径。
path 表示此web应用程序的url的前缀,这样请求的url为http://localhost:8080/path/****
reloadable 这个属性非常重要,如果为true,则tomcat会自动检测应用程序的/WEB-INF/lib和/WEB-INF/classes目录的变化,自动装载新的应用程序,可以在不重启tomcat的情况下改变应用程序

6、WEB站点部署

上线的代码有两种方式:

第一种方式是直接将程序目录放在webapps目录下面,这种方式大家已经明白了,就不多说了。

第二种方式是使用开发工具将程序打包成war包,然后上传到webapps目录下面。

1、使用war包部署web站点
[root@web03 webapps]# pwd
/application/tomcat/webapps
[root@web03 webapps]# wget http://10.0.0.1/apache/tomcat/memtest.war

站点主动解压部署

[root@web03 webapps]# ls
docs  examples  host-manager  logs  manager  memtest  memtest.war  ROOT

浏览器访问:

http://10.0.0.17:8080//memtest/meminfo.jsp

2、自定义默认网站目录

上面访问的网址为 http://10.0.0.3:8080/memtest/meminfo.jsp

现在想访问格式为http://10.0.0.3:8080/meminfo.jsp

方法一

将meminfo.jsp或其他程序放在tomcat/webapps/ROOT目录下即可。因为默认网站根目录为tomcat/webapps/ROOT

方法二

[root@web03 ~]# vim /application/tomcat/conf/server.xml +125
…… #添加上这两行
        <Context path="" docBase="/application/tomcat/webapps/memtest" debug="0" reloadable="false" crossContext="true"/>
        <Context path="/40team" docBase="/application/tomcat/webapps/memtest" debug="0" reloadable="false" crossContext="true"/>
……

修改配置文件后,要重启服务

[root@web03 ~]# /application/tomcat/bin/shutdown.sh 
[root@web03 ~]# /application/tomcat/bin/startup.sh  
3、部署开源站点(jpress)

jpress官网:http://jpress.io

下载地址:https://github.com/JpressProjects/jpress

​ 第一个里程碑:安装配置数据库

yum -y install mariadb-server
systemctl start mariadb.service

​ #配置数据库

mysql
create database jpress DEFAULT CHARACTER SET utf8;
grant all on jpress.* to jpress@'localhost' identified by '123456';
exit

​ 第二个里程碑:jpress站点上线

[root@web03 webapps]# pwd
/application/tomcat/webapps
[root@web03 webapps]# wget http://10.0.0.1/apache/tomcat/jpress-web-newest.war

​ 第三个里程碑:浏览器访问

浏览器访问: http://10.0.0.17:8080/jpress-web-newest/install

填写数据库信息

设置站点名称等

安装完成

重启tomcat服务

[root@web03 ~]# /application/tomcat/bin/shutdown.sh 
[root@web03 ~]# /application/tomcat/bin/startup.sh  

7、Tomcat多实例配置

多虚拟主机:nginx 多个Server标签(域名,ip,端口) 进程数量固定 master+worker

多实例(多进程):同一个程序启动多次,分为两种情况:

第一种:一台机器跑多个站点;

第二种:一个机器跑一个站点多个实例,配合负载均衡

1、复制程序文件
    cd /application/tools/
    tar xf apache-tomcat-8.0.27.tar.gz
    cp -a apache-tomcat-8.0.27 tomcat8_1
    cp -a apache-tomcat-8.0.27 tomcat8_2

修改端口,以启动多实例。多实例之间端口不能一致

sed -i 's#8005#8011#;s#8080#8081#' tomcat8_1/conf/server.xml
sed -i 's#8005#8012#;s#8080#8082#' tomcat8_2/conf/server.xml
[root@web03 application]# diff tomcat8_1/conf/server.xml tomcat8_2/conf/server.xml
22c22
< <Server port="8011" shutdown="SHUTDOWN">
---
> <Server port="8012" shutdown="SHUTDOWN">
67c67
<          Define a non-SSL/TLS HTTP/1.1 Connector on port 8081
---
>          Define a non-SSL/TLS HTTP/1.1 Connector on port 8082
69c69
<     <Connector port="8081" protocol="HTTP/1.1"
---
>     <Connector port="8082" protocol="HTTP/1.1"
75c75
<                port="8081" protocol="HTTP/1.1"
---
>                port="8082" protocol="HTTP/1.1"

   将配置好的tomcat程序打包,以备之后使用

tar zcf muti_tomcat8.tar.gz ./tomcat8_1 ./tomcat8_2

启动tomcat多实例

 /application/tomcat8_1/bin/startup.sh 
 /application/tomcat8_2/bin/startup.sh

检查端口是否启动

[root@web03 tomcat8_1]# netstat -lntup |grep java
tcp6   0   0 127.0.0.1:8011    :::*    LISTEN   31906/java
tcp6   0   0 127.0.0.1:8012    :::*    LISTEN   31932/java
tcp6   0   0 :::8080           :::*    LISTEN   31812/java
tcp6   0   0 :::8081           :::*    LISTEN   31906/java
tcp6   0   0 :::8082           :::*    LISTEN   31932/java
tcp6   0   0 127.0.0.1:8005    :::*    LISTEN   31812/java
tcp6   0   0 :::8009           :::*    LISTEN   31812/java

将每个实例的网页进行区分

echo 8081 >>/application/tomcat8_1/webapps/ROOT/index.jsp 
echo 8082 >>/application/tomcat8_2/webapps/ROOT/index.jsp
2、在浏览器访问,进行测试

检查多实例的启动

http://10.0.0.17:8082

http://10.0.0.17:8081

8、监控tomcat集群状态

1、开发java监控页面
[root@web03 tomcat8_1]# cat /application/tomcat/webapps/memtest/meminfo.jsp 
<%
Runtime rtm = Runtime.getRuntime();
long mm = rtm.maxMemory()/1024/1024;
long tm = rtm.totalMemory()/1024/1024;
long fm = rtm.freeMemory()/1024/1024;

out.println("JVM memory detail info :<br>");
out.println("Max memory:"+mm+"MB"+"<br>");
out.println("Total memory:"+tm+"MB"+"<br>");
out.println("Free memory:"+fm+"MB"+"<br>");
out.println("Available memory can be used is :"+(mm+fm-tm)+"MB"+"<br>");
%>
2、方法二:使用jps命令进行监控
[root@web03 ~]# jps -lvm

31906 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/application/tomcat8_1/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/application/tomcat8_1/endorsed -Dcatalina.base=/application/tomcat8_1 -Dcatalina.home=/application/tomcat8_1 -Djava.io.tmpdir=/application/tomcat8_1/temp

31812 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/application/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/application/tomcat/endorsed -Dcatalina.base=/application/tomcat -Dcatalina.home=/application/tomcat -Djava.io.tmpdir=/application/tomcat/temp

31932 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/application/tomcat8_2/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/application/tomcat8_2/endorsed -Dcatalina.base=/application/tomcat8_2 -Dcatalina.home=/application/tomcat8_2 -Djava.io.tmpdir=/application/tomcat8_2/temp

32079 sun.tools.jps.Jps -lvm -Denv.class.path=.:/application/jdk/lib:/application/jdk/jre/lib:/application/jdk/lib/tools.jar -Dapplication.home=/application/jdk1.8.0_60 -Xms8m
3、zabbix监控tomcat程序

zabbix搭建详情参考:http://www.cnblogs.com/clsn/p/7885990.html

服务端安装配置java****监控服务

[root@m01 ~]# yum install zabbix-java-gateway -y

查看配置文件

配置文件路径:/etc/zabbix/zabbix_java_gateway.conf
sed -i -e '220a JavaGateway=127.0.0.1' -e '236a StartJavaPollers=5'  /etc/zabbix/zabbix_server.conf

启动zabbix-java-gateway服务,与zabbix服务

systemctl start zabbix-java-gateway.service
systemctl restart zabbix-server.service

检查java端口是否开启

[root@m01 ~]# netstat -lntup |grep java
tcp6       0      0 :::10052   :::*    LISTEN      72971/java  

​ 检查java进程是否存在

[root@m01 ~]# ps -ef |grep [j]ava
zabbix    72971      1  0 11:29 ?        00:00:00 java -server -Dlogback.configurationFile=/etc/zabbix/zabbix_java_gateway_logback.xml -classpath lib:lib/android-json-4.3_r3.1.jar:lib/logback-classic-0.9.27.jar:lib/logback-core-0.9.27.jar:lib/slf4j-api-1.6.1.jar:bin/zabbix-java-gateway-3.0.13.jar -Dzabbix.pidFile=/var/run/zabbix/zabbix_java.pid -Dzabbix.timeout=3 -Dsun.rmi.transport.tcp.responseTimeout=3000 com.zabbix.gateway.JavaGateway
zabbix    73255  73226  0 11:35 ?        00:00:00 /usr/sbin/zabbix_server: java poller #1 [got 0 values in 0.000002 sec, idle 5 sec]
zabbix    73256  73226  0 11:35 ?        00:00:00 /usr/sbin/zabbix_server: java poller #2 [got 0 values in 0.000002 sec, idle 5 sec]
zabbix    73257  73226  0 11:35 ?        00:00:00 /usr/sbin/zabbix_server: java poller #3 [got 0 values in 0.000002 sec, idle 5 sec]
zabbix    73258  73226  0 11:35 ?        00:00:00 /usr/sbin/zabbix_server: java poller #4 [got 0 values in 0.000002 sec, idle 5 sec]
zabbix    73259  73226  0 11:35 ?        00:00:00 /usr/sbin/zabbix_server: java poller #5 [got 0 values in 0.000004 sec, idle 5 sec]

web****界面添加

​ 添加主机

​ 主机管理模板,注意是JMX模板

​ 监控完成

4、排除tomcat故障步骤

a. 查看catalina.out

b. 使用sh show-busy-java-threads.sh脚本进行检测

脚本下载地址

https://files.cnblogs.com/files/clsn/show-busy-java-threads.sh

9、Tomcat安全优化

1、telnet管理端口保护(强制)
类别 配置内容及说明 标准配置 备注
telnet管理端口保护 1.修改默认的8005管理端口为不易猜测的端口(大于1024);2.修改SHUTDOWN指令为其他字符串; 1.以上配置项的配置内容只是建议配置,可以按照服务实际情况进行合理配置,但要求端口配置在8000~8999之间;
2、 ajp连接端口保护(推荐)
类别 配置内容及说明 标准配置 备注
Ajp 连接端口保护 1.修改默认的ajp 8009端口为不易冲突的大于1024端口;2.通过iptables规则限制ajp端口访问的权限仅为线上机器; <Connector port="8528"protocol="AJP/1.3" /> 以上配置项的配置内容仅为建议配置,请按照服务实际情况进行合理配置,但要求端口配置在8000~8999之间;;保护此端口的目的在于防止线下的测试流量被mod_jk转发至线上tomcat服务器;
3、禁用管理端(强制)
类别 配置内容及说明 标准配置 备注
禁用管理端 1. 删除默认的{Tomcat安装目录}/conf/tomcat-users.xml文件,重启tomcat后将会自动生成新的文件;2. 删除{Tomcat安装目录}/webapps下默认的所有目录和文件;3.将tomcat 应用根目录配置为tomcat安装目录以外的目录; <Context path="" docBase="/home/work/local/tomcat****_webapps"debug="0"reloadable="false"crossContext="true"/> 对于前段web模块,Tomcat管理端属于tomcat的高危安全隐患,一旦被攻破,黑客通过上传web shell的方式将会直接取得服务器的控制权,后果极其严重;
4、降权启动(强制)
类别 配置内容及说明 标准配置 备注
降权启动 1.tomcat启动用户权限必须为非root权限,尽量降低tomcat启动用户的目录访问权限;2.如需直接对外使用80端口,可通过普通账号启动后,配置iptables规则进行转发; 避免一旦tomcat 服务被入侵,黑客直接获取高级用户权限危害整个server的安全;
[root@web03 ~]# useradd tomcat
[root@web03 ~]# cp -a /application/tools/tomcat8_1 /home/tomcat/
[root@web03 ~]# chown -R tomcat.tomcat /home/tomcat/tomcat8_1/
[root@web03 ~]# su -c '/home/tomcat/tomcat8_1/bin/startup.sh' tomcat
Using CATALINA_BASE:   /home/tomcat/tomcat8_1
Using CATALINA_HOME:   /home/tomcat/tomcat8_1
Using CATALINA_TMPDIR: /home/tomcat/tomcat8_1/temp
Using JRE_HOME:        /application/jdk
Using CLASSPATH:       /home/tomcat/tomcat8_1/bin/bootstrap.jar:/home/tomcat/tomcat8_1/bin/tomcat-juli.jar
Tomcat started.
[root@web03 ~]# ps -ef|grep tomcat
5、文件列表访问控制(强制)
类别 配置内容及说明 标准配置 备注
文件列表访问控制 1.conf/web.xml文件中default部分listings的配置必须为false; listingsfalse false为不列出目录文件,true为允许列出,默认为false;
6、版本信息隐藏(强制)
类别 配置内容及说明 标准配置 备注
版本信息隐藏 1.修改conf/web.xml,重定向403、404以及500等错误到指定的错误页面;2.也可以通过修改应用程序目录下的WEB-INF/web.xml下的配置进行错误页面的重定向; 403/forbidden.jsp404/notfound.jsp500/systembusy.jsp 在配置中对一些常见错误进行重定向,避免当出现错误时tomcat默认显示的错误页面暴露服务器和版本信息;必须确保程序根目录下的错误页面已经存在;
7、Server header重写(推荐)
类别 配置内容及说明 标准配置 备注
Server header重写 在HTTP Connector配置中加入server的配置; server="webserver" 当tomcat HTTP端口直接提供web服务时此配置生效,加入此配置,将会替换http 响应Server header部分的默认配置,默认是Apache-Coyote/1.1
8、访问限制(可选)
类别 配置内容及说明 标准配置或操作 备注
访问限制 通过配置,限定访问的ip来源 <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="61.148.18.138,61.135.165.*" deny="*.*.*.*"/> 通过配置信任ip的白名单,拒绝非白名单ip的访问,此配置主要是针对高保密级别的系统,一般产品线不需要;
9、起停脚本权限回收(推荐)
类别 配置内容及说明 标准配置或操作 备注
起停脚本权限回收 去除其他用户对Tomcat的bin目录下shutdown.sh、startup.sh、catalina.sh的可执行权限; chmod -R 744 tomcat/bin/* 防止其他用户有起停线上Tomcat的权限;
10、 访问日志格式规范(推荐)
类别 配置内容及说明 标准配置或操作 备注
访问日志格式规范 开启Tomcat默认访问日志中的Referer和User-Agent记录 开启Referer和User-Agent是为了一旦出现安全问题能够更好的根据日志进行问题排查;
11、 附录:建议配置及标准执行方案

1. 配置部分(${ CATALINA_HOME }conf/server.xml

<Server port="8527" shutdown=" dangerous">

<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<Connector port="8080" server="webserver"/> 

<!-- Define an AJP 1.3 Connector on port 8528 -->
<!--Define an accesslog --> 
<Valve className="org.apache.catalina.valves.AccessLogValve"
                 directory="logs"  prefix="localhost_access_log." suffix=".txt"
                 pattern="%h %l %u %t %r %s %b %{Referer}i %{User-Agent}i %D" resolveHosts="false"/>

    <Connector port="8528" protocol="AJP/1.3" />

<Context path="" docBase="/home/work/local/tomcat_webapps" debug="0" reloadable="false" crossContext="true"/>

2. 配置部分(${ CATALINA_HOME }conf/web.xml或者WEB-INF/web.xml

<init-param>
    <param-name>listings</param-name>
    <param-value>false</param-value>
</init-param>

<error-page>
    <error-code>403</error-code>
    <location>/forbidden.jsp</location>
</error-page>
<error-page>
    <error-code>404</error-code>
    <location>/notfound.jsp</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/systembusy.jsp</location>
</error-page>

3. 删除如下tomcat的默认目录和默认文件

tomcat/webapps/*
tomcat/conf/tomcat-user.xml

4. 去除其他用户对****tomcat 起停脚本的执行权限

chmod 744 –R tomcat/bin/*

11、Tomcat性能优化

tomcat性能取决于 内存大小

上策:优化代码

该项需要开发经验足够丰富,对开发人员要求较高

中策:jvm****优化机制 垃圾回收机制 把不需要的内存回收

​ 优化jvm--优化垃圾回收策略

优化catalina.sh配置文件。在catalina.sh配置文件中添加以下代码

# tomcat分配1G内存模板
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=512m -XX:MaxPermSize=512m"        

JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms800m -Xmx800m -XX:NewSize=400m -XX:MaxNewSize=400m -XX:PermSize=400m -XX:MaxPermSize=400m"    
# 重启服务
su -c '/home/tomcat/tomcat8_1/bin/shutdown.sh' tomcat
su -c '/home/tomcat/tomcat8_1/bin/startup.sh' tomcat

下策:加足够大的内存

该项的资金投入较大

下下策:每天0****点定时重启tomcat

tern="%h %l %u %t %r %s %b %{Referer}i %{User-Agent}i %D" resolveHosts="false"/>

```

2. 配置部分(${ CATALINA_HOME }conf/web.xml或者WEB-INF/web.xml

<init-param>
    <param-name>listings</param-name>
    <param-value>false</param-value>
</init-param>

<error-page>
    <error-code>403</error-code>
    <location>/forbidden.jsp</location>
</error-page>
<error-page>
    <error-code>404</error-code>
    <location>/notfound.jsp</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/systembusy.jsp</location>
</error-page>

3. 删除如下tomcat的默认目录和默认文件

tomcat/webapps/*
tomcat/conf/tomcat-user.xml

4. 去除其他用户对****tomcat 起停脚本的执行权限

chmod 744 –R tomcat/bin/*

11、Tomcat性能优化

tomcat性能取决于 内存大小

上策:优化代码

该项需要开发经验足够丰富,对开发人员要求较高

中策:jvm****优化机制 垃圾回收机制 把不需要的内存回收

​ 优化jvm--优化垃圾回收策略

优化catalina.sh配置文件。在catalina.sh配置文件中添加以下代码

# tomcat分配1G内存模板
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=512m -XX:MaxPermSize=512m"        

JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms800m -Xmx800m -XX:NewSize=400m -XX:MaxNewSize=400m -XX:PermSize=400m -XX:MaxPermSize=400m"    
# 重启服务
su -c '/home/tomcat/tomcat8_1/bin/shutdown.sh' tomcat
su -c '/home/tomcat/tomcat8_1/bin/startup.sh' tomcat

下策:加足够大的内存

该项的资金投入较大

下下策:每天0****点定时重启tomcat

使用较为广泛