Tomcat运维


1. Tomcat介绍

1.1 什么是tomcat

  • Tomcat是Apache软件基金会的一个开源Web应用服务器

  • 主要特性:
    ✓ 实现了Java Servlet和JSP规范
    ✓ 轻量级、免费、开源
    ✓ 跨平台(Windows/Linux/macOS)
    ✓ 广泛用于Java Web开发

  • Java程序代码运行容器常见的有

    • tomcat 应用最为广泛
    • Resin
    • Jboss
    • Weblogic 结合Oracle
    • 直接通过java命令启动
  • 用户请求 → 浏览器 → HTTP协议 → Tomcat服务器 → Servlet/JSP → 数据库

1.2 Tomcat时间线

timeline
    title Tomcat版本发展
    section 早期版本
        1999 : Tomcat 3.0<br>首个Apache版本
        2001 : Tomcat 4.0<br>全新架构Catalina
    section 成熟发展
        2003 : Tomcat 5.0<br>支持Servlet 2.4
        2006 : Tomcat 6.0<br>支持Servlet 2.5
    section 现代版本
        2011 : Tomcat 7.0<br>支持Servlet 3.0
        2014 : Tomcat 8.0<br>默认NIO,支持HTTP/2
        2016 : Tomcat 9.0<br>支持Servlet 4.0
        2021 : Tomcat 10.0<br>Jakarta EE命名空间

1.3 核心架构

Tomcat
├── Server(服务器)
│   ├── Service(服务)
│   │   ├── Connector(连接器,处理网络连接)
│   │   └── Container(容器,处理业务逻辑)
│   │       ├── Engine(引擎)
│   │       │   ├── Host(虚拟主机)
│   │       │   │   ├── Context(Web应用)
│   │       │   │   │   ├── Wrapper(Servlet)
│   │       │   │   │   └── Filter(过滤器)
│   │       │   │   └── Valve(阀门)
│   │       │   └── Realm(安全域)
│   └── Executor(线程池)

1. Connector(连接器)

  • 负责接收HTTP请求
  • 支持多种协议:HTTP/1.1、HTTP/2、AJP
  • 支持多种I/O模型:BIO、NIO、NIO2、APR

2. Container(容器)

  • Engine:顶级容器,管理多个Host
  • Host:虚拟主机,对应域名
  • Context:Web应用程序上下文
  • Wrapper:Servlet包装器

3. 处理流程

  1. 请求到达Connector
  2. Connector解析请求,创建Request/Response对象
  3. 传递到Engine容器
  4. 根据Host配置选择虚拟主机
  5. 根据URL找到对应的Context
  6. 执行Filter链
  7. 调用对应的Servlet
  8. 返回响应

2. 安装与配置

2.1 安装jdk

# 解压到对应的目录下
[root@localhost ~]# mkdir -p /server/tools/
[root@localhost ~]# mkdir -p /app/tools/
[root@localhost tools]# cd /server/tools/
[root@localhost tools]# tar xzvf jdk-8u151-linux-x64.tar.gz -C /app/tools/
[root@localhost tools]# /app/tools/jdk/bin/java -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

# 添加环境变量
[root@localhost tools]# cat >>/etc/profile<<'EOF'
export JAVA_HOME=/app/tools/jdk
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
export TOMCAT_HOME=/app/tools/tomcat
EOF

[root@localhost ~]# source /etc/profile
[root@localhost ~]# java -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)

2.2 安装tomcat

[root@localhost ~]# cd /server/tools/
[root@localhost tools]# tar xzvf apache-tomcat-9.0.113.tar.gz -C /app/tools/
[root@localhost tools]# ln -s /app/tools/apache-tomcat-9.0.113/ /app/tools/tomcat
[root@localhost ~]# /app/tools/tomcat/bin/version.sh 
Using CATALINA_BASE:   /app/tools/tomcat
Using CATALINA_HOME:   /app/tools/tomcat
Using CATALINA_TMPDIR: /app/tools/tomcat/temp
Using JRE_HOME:        /app/tools/jdk
Using CLASSPATH:       /app/tools/tomcat/bin/bootstrap.jar:/app/tools/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:   
Server version: Apache Tomcat/9.0.113
Server built:   Dec 2 2025 19:51:24 UTC
Server number:  9.0.113.0
OS Name:        Linux
OS Version:     5.14.0-503.14.1.el9_5.x86_64
Architecture:   amd64
JVM Version:    1.8.0_151-b12
JVM Vendor:     Oracle Corporation
  • 启动tomcat
[root@localhost ~]# /app/tools/tomcat/bin/startup.sh 
Using CATALINA_BASE:   /app/tools/tomcat
Using CATALINA_HOME:   /app/tools/tomcat
Using CATALINA_TMPDIR: /app/tools/tomcat/temp
Using JRE_HOME:        /app/tools/jdk
Using CLASSPATH:       /app/tools/tomcat/bin/bootstrap.jar:/app/tools/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:   
Tomcat started.
[root@localhost ~]# ss -ntlp |grep java
LISTEN 0      100                     *:8080            *:*    users:(("java",pid=3321,fd=56))
LISTEN 0      1      [::ffff:127.0.0.1]:8005            *:*    users:(("java",pid=3321,fd=65))
[root@localhost ~]# ps -ef |grep java
root        3321       1 10 09:36 pts/0    00:00:06 /app/tools/jdk/bin/java -Djava.util.logging.config.file=/app/tools/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djav.protocol.handler.pkgs=org.apache.catalina.webresources -Dsun.io.useCanonCaches=false -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /app/tools/tomcat/bin/bootstrap.jar:/app/tools/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/app/tools/tomcat -Dcatalina.home=/app/tools/tomcat -Djava.io.tmpdir=/app/tools/tomcat/temp org.apache.catalina.startup.Bootstrap start
root        3361    2719  0 09:37 pts/0    00:00:00 grep --color=auto java
  • 浏览器访问

3. 目录结构

目录 说明
bin 存放 tomcat 管理脚本
conf 配置文件目录
logs 日志目录
webapps 站点目录
lib tomcat 依赖的 .jar 文件所在目录
temp 临时目录
work tomcat 运行代码的编译临时目录 (tomcat 运行生成产物)

3.1 bin目录

脚本文件 功能说明
startup.sh 启动 Tomcat
shutdown.sh 关闭 Tomcat
catalina.sh Tomcat 的核心脚本,启动和关闭时均会调用。支持 JVM 优化配置,并可开启 Tomcat 监控功能。

3.2 conf目录

文件 功能说明
server.xml 类似于 nginx.conf 主配置文件
web.xml 配置 Tomcat 内置功能
logging.properties 日志格式 (properties属性)
tomcat-users.xml Tomcat 管理端配置文件 (线上环境中关闭)

3.3 logs目录

日志文件 功能说明
catalina.out Tomcat 主要运行日志,包含启动、关闭、运行状态等信息。每日切割后,此文件不会清空,仍会持续增大。
catalina.2026-11-26.log Tomcat 每日对 catalina.out 日志进行切割后生成的归档日志文件,内容类似。
localhost_access_log.2026-11-26.txt Tomcat 的访问日志,记录客户端请求信息。
host-manager.2026-11-26.log Tomcat 主机管理应用的专用日志。
localhost.2026-11-26.log Tomcat 本地的应用日志,通常与特定应用相关。
manager.2026-11-26.log Tomcat 管理应用的专用日志。

4. 基础使用

  • tomcat 部署(运行) app
  • tomcat 日志查看
  • tomcat systemctl 管理脚本

4.1 部署app

  • 方式01-war包(压缩包)放到站点目录下面
  • 方式02-jar包 java -jar xxx.jar 运行java app
  • war包部署到tomcat webapps下面自动解压,自动部署(jvm)
[root@localhost webapps]# ll -h
total 12K
drwxr-x---  3 root root 4.0K Dec 28 09:34 ROOT
drwxr-x--- 16 root root 4.0K Dec 28 09:34 docs
drwxr-x---  7 root root   99 Dec 28 09:34 examples
drwxr-x---  6 root root   79 Dec 28 09:34 host-manager
drwxr-x---  6 root root  114 Dec 28 09:34 manager
drwxr-x---  3 root root   41 Dec 28 09:57 memtest				# 自动解压出来的war
-rw-r--r--  1 root root  643 Dec 28 09:56 memtest.war			# 复制进来的war包
  • 访问查看
  • jar 包方式运行
[root@localhost ~]# java -jar halo-1.0.0-beta.3.jar --server.port=8082

4.2 日志查看

  • 开关日志
[root@localhost tomcat]# tail -f /app/tools/tomcat/logs/catalina.out
# info表示通知或提示,正常状态
# error failed exception(异常) 不正常情况上下几行看错误原因
# startup 应用已经启动
# finished  应用部署完成
  • 部署服务的日志
  • 访问日志
[root@localhost tomcat]# tail -f /app/tools/tomcat/logs/localhost_access_log.2026-12-28.txt

4.3 systemctl配置

# 环境变量配置文件(yum 安装 jdk 可以忽略)
[root@localhost ~]# cat /etc/sysconfig/tomcat 
JAVA_HOME=/app/tools/jdk
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar

# 配置service文件
[root@localhost ~]# cat /usr/lib/systemd/system/tomcat.service 
[Unit]
Description=The tomcat web server by Apache
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
EnvironmentFile=/etc/sysconfig/tomcat
ExecStart=/app/tools/tomcat/bin/startup.sh
ExecStop=/app/tools/tomcat/bin/shutdown.sh
ExecReload=/app/tools/tomcat/bin/shutdown.sh && sleep 2 && /app/tools/tomcat/bin/startup.sh

[Install]
WantedBy=multi-user.target


[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl start tomcat		# 需要先关闭之前脚本启动的tomcat实例

4.4 管理端

  • 需要添加两个规则名称,就可以开启图形化管理了manager-gui, admin-gui
  • 默认情况下,管理页面仅供本机访问,需要修改允许访问的地址

    [root@localhost ~]# cp /app/tools/tomcat/conf/tomcat-users.xml{,.old}
    [root@localhost ~]# cat /app/tools/tomcat/conf/tomcat-users.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <tomcat-users xmlns="http://tomcat.apache.org/xml"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
                  version="1.0">
      <role rolename="manager-gui"/>
      <role rolename="admin-gui"/>
      <user username="tomcat" password="tomcat" roles="manager-gui,admin-gui"/>
    </tomcat-users>
    
    # 注意修改本地地址的时候,旧版本使用的正则,需要提前打开这两个文件确认
    [root@localhost ~]# sed -i 's#127.0.0.0\/8#0.0.0.0\/0#g' /app/tools/tomcat/webapps/host-manager/META-INF/context.xml /app/tools/tomcat/webapps/manager/META-INF/context.xml 
    [root@localhost ~]# systemctl restart tomcat
  • 可以正常打开

4.5 主配置文件

[root@localhost ~]# cp /app/tools/tomcat/conf/server.xml{,.old}
[root@localhost ~]# cat /app/tools/tomcat/conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- tomcat的shutdown端口,连接此端口,输入暗号SHUTDOWN关闭tomcat -->
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
  <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 name="Catalina">
  <!-- 用户请求 进入到connector中 连接机器 -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
               maxParameterCount="1000"
               />
  <!-- 交给Engine部分处理 指定默认的 host (默认的虚拟主机) -->
    <Engine name="Catalina" defaultHost="localhost">
    <!-- Realm认证的方式,不需要可以删除 -->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <!-- host 虚拟主机部分的配置, name就是域名, appBase是网站根目录, unpackWARs自动解压war包,autoDeploy自动加载到jvm中 -->
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <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" />
             <!-- directory 存放日志的目录 -->
             <!-- prefix 日志前缀 -->
             <!-- suffix 日志后缀 -->
             <!-- pattern 日志名中间拼接的格式 -->
      </Host>
    </Engine>
  </Service>
</Server>
Tomcat访问日志格式 tomcat nginx
客户端ip地址 %h $remote_addr
用户名 %l
用户名 %u
日期和时间 %t $local_time
用户请求的起始行(请求方法和uri) %r $request
状态码 %s $status
响应的大小(服务端—>客户端) %b $body_bytes_sent
用户从哪里跳转来的 ${Referer}i ${http_referer}
用户的客户端 ${User-Agent}i ${http_user_agent}
用户的真实ip地址 ${X-Forwarded-For}i ${http_x_forwarded_for}
  • 8005关闭端口
    • 访问此端口,然后发送SHUTDOWN,就可以关闭tomcat
[root@localhost ~]# telnet 127.0.0.1 8005
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SHUTDOWN
Connection closed by foreign host.
[root@localhost ~]# systemctl status tomcat
○ tomcat.service - The tomcat web server by Apache
     Loaded: loaded (/usr/lib/systemd/system/tomcat.service; disabled; preset: disabled)
     Active: inactive (dead)
  • tomcat常见默认端口

    • 8080 web端口
    • 8005 shutdown端口
    • 8009 ajp端口(从 tomcat 8.5 默认关闭) tomcat与apache连接使用端口
    • 8443 https端口
  • tomcat 处理用户请求

    • 用户发出请求
    • 请求到达tomcat connector 部分
    • 交给engine部分的host部分处理(虚拟主机)
    • 处理返回给用户

4.6 虚拟主机

虚拟主机域名 站点目录 访问日志
localhost webapps access.时间.log
live.iproute.cn live access.时间.log
bbs.iproute.cn bbs access.时间.log
  • 主配置文件
[root@localhost ~]# cat /app/tools/tomcat/conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
  <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 name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
               maxParameterCount="1000"
               />
    <Engine name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <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>
      <Host name="live.iproute.cn"  appBase="live"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="access" suffix=".log"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
      <Host name="bbs.iproute.cn"  appBase="bbs"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="access" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>
[root@localhost ~]# mkdir -p /app/tools/tomcat/{live,bbs}/ROOT
[root@localhost ~]# echo bbs > /app/tools/tomcat/bbs/ROOT/index.jsp
[root@localhost ~]# echo live > /app/tools/tomcat/live/ROOT/index.jsp

4.7 部署app

  • 创建虚拟主机,并且设置为默认站点
[root@localhost ~]# cat /app/tools/tomcat/conf/server.xml
.......
    <Engine name="Catalina" defaultHost="zrlog.iproute.cn">
......
      <Host name="zrlog.iproute.cn"  appBase="zrlog"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="access" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
.......

[root@localhost ~]# mkdir /app/tools/tomcat/zrlog		# 将war包放到这个目录下
[root@localhost tomcat]# cat logs/catalina.out |grep zrlog.war
28-Dec-2025 14:31:59.131 INFO [Catalina-utility-2] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [/app/tools/apache-tomcat-9.0.113/zrlog/zrlog.war]
28-Dec-2025 14:32:00.664 INFO [Catalina-utility-2] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/app/tools/apache-tomcat-9.0.113/zrlog/zrlog.war] has finished in [1,533] ms
[root@localhost zrlog]# pwd
/app/tools/tomcat/zrlog
[root@localhost zrlog]# mkdir ROOT
[root@localhost zrlog]# mv zrlog/* ROOT
[root@localhost tomcat]# systemctl restart tomcat
  • 准备一个mysql数据库,并且进行连接
[root@node01 ~]# docker run -v "$PWD/data":/var/lib/mysql -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6
[root@node01 ~]# docker exec -it mysql bash
root@674cbb277672:/# mysql -uroot -p123456
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.51 MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database zrlog;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| zrlog              |
+--------------------+
4 rows in set (0.00 sec)

mysql> \q
Bye
  • 正确配置博客系统
  • 上传图片
[root@localhost tomcat]# ll -h zrlog/ROOT/attached/image/20251228/
total 184K
-rw-r----- 1 root root 181K Dec 28 15:08 20251228150830_440.png
  • 如果需要修改数据库设置可以搜索数据库的配置文件
[root@localhost tomcat]# grep -R 172.16.17.8 zrlog/
zrlog/zrlog-2.2.1-efbe9f9-release/WEB-INF/db.properties:jdbcUrl=jdbc\:mysql\://172.16.17.8\:3306/zrlog?characterEncoding\=UTF-8&allowPublicKeyRetrieval\=true&useSSL\=false&serverTimezone\=GMT
zrlog/ROOT/WEB-INF/db.properties:jdbcUrl=jdbc\:mysql\://172.16.17.8\:3306/zrlog?characterEncoding\=UTF-8&allowPublicKeyRetrieval\=true&useSSL\=false&serverTimezone\=GMT

[root@localhost tomcat]# cat zrlog/ROOT/WEB-INF/db.properties
#This is a database configuration file
#Sun Dec 28 15:05:45 CST 2025
driverClass=com.mysql.cj.jdbc.Driver
user=root
password=123456
jdbcUrl=jdbc\:mysql\://172.16.17.8\:3306/zrlog?characterEncoding\=UTF-8&allowPublicKeyRetrieval\=true&useSSL\=false&serverTimezone\=GMT

5. 多实例

  • 多实例: 在同一台机器运行多个tomcat,充分利用服务器资源

  • 注意事项

    :one: 共用jdk环境

    :two: 复制多份tomcat并修改每个tomcat的端口(8080, 8005, 8443) tomcat_8080 tomcat_8081 tomcat_8082

    :three: 指定不同的代码目录(推荐每个代码放在tomcat 默认在webapps/ROOT)

  • tomcat

    • conf/server.xml(8080, 8005)
    • webapps/ROOT/zrlog 代码
  • tomcat_8081
    • conf/server.xml(8081, 8006)
    • webapps/ROOT/zrlog 代码
  • tomcat_8082
    • conf/server.xml(8082, 8007)
    • webapps/ROOT/zrlog 代码
[root@localhost tools]# cp -r tomcat/ tomcat_8081
[root@localhost tools]# cp -r tomcat/ tomcat_8082
[root@localhost tools]# ll
total 16
drwxr-xr-x 12 root root 4096 Dec 28 14:29 apache-tomcat-9.0.113
lrwxrwxrwx  1 root root   24 Dec 27 17:26 jdk -> /app/tools/jdk1.8.0_151/
drwxr-xr-x  8   10  143 4096 Sep  6  2017 jdk1.8.0_151
lrwxrwxrwx  1 root root   33 Dec 28 09:34 tomcat -> /app/tools/apache-tomcat-9.0.113/
drwxr-xr-x 12 root root 4096 Dec 28 15:24 tomcat_8081
drwxr-xr-x 12 root root 4096 Dec 28 15:24 tomcat_8082
[root@localhost tools]# sed -i 's#8080#8081#g' tomcat_8081/conf/server.xml
[root@localhost tools]# sed -i 's#8080#8082#g' tomcat_8082/conf/server.xml
[root@localhost tools]# sed -i 's#8005#8006#g' tomcat_8081/conf/server.xml
[root@localhost tools]# sed -i 's#8005#8007#g' tomcat_8082/conf/server.xml
[root@localhost tools]# /app/tools/tomcat_8081/bin/startup.sh 
Using CATALINA_BASE:   /app/tools/tomcat_8081
Using CATALINA_HOME:   /app/tools/tomcat_8081
Using CATALINA_TMPDIR: /app/tools/tomcat_8081/temp
Using JRE_HOME:        /app/tools/jdk
Using CLASSPATH:       /app/tools/tomcat_8081/bin/bootstrap.jar:/app/tools/tomcat_8081/bin/tomcat-juli.jar
Using CATALINA_OPTS:   
Tomcat started.
[root@localhost tools]# /app/tools/tomcat_8082/bin/startup.sh 
Using CATALINA_BASE:   /app/tools/tomcat_8082
Using CATALINA_HOME:   /app/tools/tomcat_8082
Using CATALINA_TMPDIR: /app/tools/tomcat_8082/temp
Using JRE_HOME:        /app/tools/jdk
Using CLASSPATH:       /app/tools/tomcat_8082/bin/bootstrap.jar:/app/tools/tomcat_8082/bin/tomcat-juli.jar
Using CATALINA_OPTS:   
Tomcat started.
[root@localhost tools]# ss -ntlp |grep java
LISTEN 0      100                     *:8080            *:*    users:(("java",pid=4764,fd=56))
LISTEN 0      100                     *:8081            *:*    users:(("java",pid=4994,fd=56))
LISTEN 0      100                     *:8082            *:*    users:(("java",pid=5055,fd=56))
LISTEN 0      1      [::ffff:127.0.0.1]:8005            *:*    users:(("java",pid=4764,fd=68))
LISTEN 0      1      [::ffff:127.0.0.1]:8007            *:*    users:(("java",pid=5055,fd=74))
LISTEN 0      1      [::ffff:127.0.0.1]:8006            *:*    users:(("java",pid=4994,fd=74))
  • 访问页面测试

6. 资源监控

  • 检查tomcat状态(jvm状态)
  • 命令行命令
  • 命令行脚本
  • 配置远程监控功能(zabbix)

6.1 java环境监控命令

  • jps命令
[root@localhost ~]# jps
5217 Jps
4994 Bootstrap
4764 Bootstrap
5055 Bootstrap
# java的进程信息,启动命令
[root@localhost ~]# jps -lvm
4994 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/app/tools/tomcat_8081/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dsun.io.useCanonCaches=false -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -Dcatalina.base=/app/tools/tomcat_8081 -Dcatalina.home=/app/tools/tomcat_8081 -Djava.io.tmpdir=/app/tools/tomcat_8081/temp
4764 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/app/tools/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dsun.io.useCanonCaches=false -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -Dcatalina.base=/app/tools/tomcat -Dcatalina.home=/app/tools/tomcat -Djava.io.tmpdir=/app/tools/tomcat/temp
5277 sun.tools.jps.Jps -lvm -Denv.class.path=.:/app/tools/jdk/lib:/app/tools/jdk/jre/lib:/app/tools/jdk/lib/tools.jar -Dapplication.home=/app/tools/jdk1.8.0_151 -Xms8m
5055 org.apache.catalina.startup.Bootstrap start -Djava.util.logging.config.file=/app/tools/tomcat_8082/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dsun.io.useCanonCaches=false -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -Dcatalina.base=/app/tools/tomcat_8082 -Dcatalina.home=/app/tools/tomcat_8082 -Djava.io.tmpdir=/app/tools/tomcat_8082/temp

# jvm信息,内存信息
[root@localhost ~]# jmap 4994
Attaching to process ID 4994, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.151-b12
0x0000000000400000	7K	/app/tools/jdk1.8.0_151/bin/java
0x00007fe16fc00000	251K	/app/tools/jdk1.8.0_151/jre/lib/amd64/libsunec.so
0x00007fe174200000	49K	/app/tools/jdk1.8.0_151/jre/lib/amd64/libmanagement.so
0x00007fe176000000	113K	/app/tools/jdk1.8.0_151/jre/lib/amd64/libnet.so
0x00007fe176400000	90K	/app/tools/jdk1.8.0_151/jre/lib/amd64/libnio.so
0x00007fe18401f000	105K	/usr/lib64/libgcc_s-11-20240719.so.1
0x00007fe199800000	125K	/app/tools/jdk1.8.0_151/jre/lib/amd64/libzip.so
0x00007fe199c00000	220K	/app/tools/jdk1.8.0_151/jre/lib/amd64/libjava.so
0x00007fe19a000000	64K	/app/tools/jdk1.8.0_151/jre/lib/amd64/libverify.so
0x00007fe19a400000	16615K	/app/tools/jdk1.8.0_151/jre/lib/amd64/server/libjvm.so
0x00007fe19b400000	2484K	/usr/lib64/libc.so.6
0x00007fe19b616000	52K	/usr/lib64/libnss_sss.so.2
0x00007fe19b725000	891K	/usr/lib64/libm.so.6
0x00007fe19b800000	101K	/app/tools/jdk1.8.0_151/lib/amd64/jli/libjli.so
0x00007fe19ba27000	15K	/usr/lib64/librt.so.1
0x00007fe19ba2e000	15K	/usr/lib64/libdl.so.2
0x00007fe19ba33000	15K	/usr/lib64/libpthread.so.0
0x00007fe19ba3e000	871K	/usr/lib64/ld-linux-x86-64.so.2

# jvm的gc信息
[root@localhost ~]# jstat -gc 4994
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
23552.0 24576.0  0.0    0.0   187904.0 161792.2  89088.0    21770.2   35416.0 34395.2 4224.0 3874.2      9    0.163   2      0.162    0.325

# Java进程信息
[root@localhost ~]# jstack 4994
"main" #1 prio=5 os_prio=0 tid=0x00007fe19400a800 nid=0x1383 runnable [0x00007fe19b722000]
   java.lang.Thread.State: RUNNABLE
	at java.net.PlainSocketImpl.socketAccept(Native Method)
	at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
	at java.net.ServerSocket.implAccept(ServerSocket.java:545)
	at java.net.ServerSocket.accept(ServerSocket.java:513)
	at org.apache.catalina.core.StandardServer.await(StandardServer.java:559)
	at org.apache.catalina.startup.Catalina.await(Catalina.java:826)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:774)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:342)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473)

6.2 java环境监控脚本

# 查看Java进程繁忙程度
[root@localhost ~]# sh show-busy-java-threads.sh 
Busy(0.2%) thread(5072/0x13d0) stack of java process(5055) under user(root):
"C2 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f8e480c8000 nid=0x13d0 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

Busy(0.2%) thread(5070/0x13ce) stack of java process(5055) under user(root):
"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f8e480c3000 nid=0x13ce waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

Busy(0.2%) thread(5009/0x1391) stack of java process(4994) under user(root):
"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007fe1940c6000 nid=0x1391 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

Busy(0.2%) thread(4779/0x12ab) stack of java process(4764) under user(root):
"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f33b40c6000 nid=0x12ab waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

Busy(0.2%) thread(4778/0x12aa) stack of java process(4764) under user(root):
"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f33b40c3000 nid=0x12aa waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

6.3 Tomcat远程监控功能

  • 通过监控工具获取tomcat里面jvm信息
    • 方法01 通过命令/脚本
    • 方法02 开启tomcat远程监控功能 jmx
[root@localhost ~]# grep -A5 ^CATALINA_OPTS= /app/tools/tomcat/bin/catalina.sh 
CATALINA_OPTS="$CATALINA_OPTS \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=12345 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=172.16.17.10"
[root@localhost ~]# systemctl restart tomcat
[root@localhost ~]# ss -ntlp |grep 12345
LISTEN 0      50                      *:12345            *:*    users:(("java",pid=6012,fd=20))
  • 通过windows jdk 工具访问tomcat(jmx)
  • jconsole.exe
  • jvisualvm.exe

  • 下载并解压后,需要配置JDK路径:

    • 打开etc/visualvm.conf配置文件

    • 找到visualvm_jdkhome配置项

    • 设置为你本地的JDK安装路径,例如:visualvm_jdkhome="C:\Program Files\Java\jdk-17"

    • 确保去掉前面的注释符号#

7. Nginx结合

7.1 不涉及负载均衡

  • nginx+tomcat组合
    • nginx处理静态资源(用户浏览器缓存,开启缓存功能)
    • tomcat处理动态资源
[root@localhost ~]# cat /etc/nginx/conf.d/zrlog.iproute.cn.conf 
server {
    listen 80;
    server_name zrlog.iproute.cn;
    root /app/tools/tomcat/zrlog/ROOT;
    location / {
        proxy_pass http://127.0.0.1:8080;
	    proxy_set_header Host $http_host;
    }
}
  • 访问测试
  • 配置静态资源缓存
[root@localhost ~]# cat /etc/nginx/conf.d/zrlog.iproute.cn.conf
server {
    listen 80;
    server_name zrlog.iproute.cn;
    root /app/tools/tomcat/zrlog/ROOT;
    location / {
        proxy_pass http://127.0.0.1:8080;
	proxy_set_header Host $http_host;
    }
    location ~* \.(js|css|html|png|jpg)$ {
        expires max;
    }
}
  • 查看缓存

7.2 负载均衡

  • nginx负载均衡
    • nginx (如果做了代码动静分离,可以使用这个)
    • 多个tomcat
  • 模拟动静分离,其中动态资源8080实例,静态资源请求的8081实例
[root@localhost ~]# cat /etc/nginx/proxy_params 
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
[root@localhost ~]# cat /etc/nginx/conf.d/zrlog.iproute.cn.conf 
upstream zrlog_default {
    server 172.16.17.10:8080;
}

upstream zrlog_static {
    server 172.16.17.10:8081;
}

server {
    listen 80;
    server_name zrlog.iproute.cn;
    location / {
        proxy_pass http://zrlog_default;
	include proxy_params;
    }
    location ~* \.(js|css|html|png|jpg)$ {
        proxy_pass http://zrlog_static;
	include proxy_params;
    }
}

[root@localhost tools]# nginx -t
[root@localhost tools]# nginx -s reload
  • 查看日志
# 静态资源从8081实例获取
[root@localhost tools]# tail -f tomcat_8081/logs/access.2025-12-29.txt 
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /assets/js/video.js?t=1624781874000 HTTP/1.0" 200 118530
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /attached/thumbnail/20251228/20251228150820_322.png?h=660&w=660 HTTP/1.0" 200 437680
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /assets/css/video-js.css?t=1624781874000 HTTP/1.0" 200 15406
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /include/templates/default/js/sheshui.js?t=1624781874000 HTTP/1.0" 200 7620
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /include/templates/default/css/editormd.css?t=1624781874000 HTTP/1.0" 200 74701
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /include/templates/default/js/jquery.min.js?t=1624781874000 HTTP/1.0" 200 86926
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /assets/js/katex/katex.min.css HTTP/1.0" 404 208
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /include/templates/default/css/style.css?t=1624781874000 HTTP/1.0" 200 51984
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /assets/js/video.js?t=1624781874000 HTTP/1.0" 200 118530
172.16.17.10 - - [29/Dec/2025:10:10:58 +0800] "GET /attached/thumbnail/20251228/20251228150820_322.png?h=660&w=660 HTTP/1.0" 200 437680
172.16.17.10 - - [29/Dec/2025:10:11:51 +0800] "GET /assets/js/katex/katex.min.css HTTP/1.0" 404 208

# 动态资源从8080实例获取
[root@localhost tools]# tail -f tomcat/logs/access.2025-12-29.txt 
172.16.17.10 - - [29/Dec/2025:10:14:20 +0800] "GET /admin HTTP/1.0" 302 -
172.16.17.10 - - [29/Dec/2025:10:14:20 +0800] "GET /admin/index HTTP/1.0" 200 10795
172.16.17.10 - - [29/Dec/2025:10:14:21 +0800] "GET /api/admin/user/basicInfo HTTP/1.0" 200 174
172.16.17.10 - - [29/Dec/2025:10:14:21 +0800] "GET /assets/images/default-portrait.gif HTTP/1.0" 200 2926
172.16.17.10 - - [29/Dec/2025:10:14:21 +0800] "GET /api/admin/serverInfo HTTP/1.0" 200 5879
172.16.17.10 - - [29/Dec/2025:10:14:21 +0800] "GET /api/admin/statisticsInfo HTTP/1.0" 200 100
172.16.17.10 - - [29/Dec/2025:10:14:21 +0800] "GET /favicon.ico HTTP/1.0" 200 16958
172.16.17.10 - - [29/Dec/2025:10:14:23 +0800] "GET /api/admin/article?page=1&size=10&key= HTTP/1.0" 200 529

8. 故障排查

8.1 开机自启动故障

  • 方法01

    • 使用systemctl 配置设置开机自启动
    • systemctl enable tomcat
  • 方法02

    • 使用/etc/rc.d/rc.local
    • 在开机或者定时任务运行脚本的时候,无法识别到自定义的PATH环境变量,没有Java相关路径
[root@localhost ~]# cat /etc/rc.local 
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.

touch /var/lock/subsys/local
. /etc/profile
/app/tools/tomcat/bin/startup.sh
[root@localhost ~]# chmod +x /etc/rc.d/rc.local

8.2 swap大量占用物理内存占用较少

  • 主要是Java代码的问题
  • 解决
    • 临时增大swap
    • 调整Linux内核参数,让系统更优先使用内存
    • 让开发解决代码的问题
[root@localhost ~]# echo 'vm.swappiness = 0' >> /etc/sysctl.conf 		# swap亲和性,越大越优先使用swap
[root@localhost ~]# sysctl -p
vm.swappiness = 0

8.3 负载高

  • 整体思路与流程
    • 定位tomcat的线程
    • 导出各种统计线程、进程信息
    • 与开发一起排查
  1. 整体排查 使用 vmstat(r cpu b io) / top / ps aux 找出哪个进程的问题。
  2. 找出进程对应线程id
    • 通过 top -Hp java进程id 找出是哪个 Java 线程的问题。
    • 或者使用 show_busy_java_threads.sh 脚本。
  3. 转换线程id为16进制 问题线程的 id 转换为 16 进制。 echo 'obase=16;1138' | bc
  4. 找出线程的详细信息 使用 jstack 显示 Java 进程信息: jstack Java进程id |grep -A 10 故障线程id 过滤 Java 线程的 16 进制 id,并与开发沟通。
  5. 显示 JVM 信息 使用 jmap 显示 Java JVM 信息: jmap -heap java进程id 显示 JVM 的内存使用情况。
  6. JVM 内存内容导出 使用 jmap 导出 JVM 内存的内容: jmap -dump:format=b,file=/root/tomcat.bin pid
  7. 分析 JVM 导出文件 通过 MAT(Eclipse Memory Analyzer Tool)在 Windows 上分析导出的文件。

9. Tomcat优化

9.1 安全优化

  • 修改Tomcat shutdown端口及暗号
[root@localhost ~]# cat /app/tools/tomcat/conf/server.xml |grep shutdown
<Server port="8555" shutdown="Dangerous">
[root@localhost ~]# systemctl restart tomcat
[root@localhost ~]# ss -ntlp |grep java
LISTEN 0      1      [::ffff:127.0.0.1]:8555             *:*    users:(("java",pid=1517,fd=71))

9.1.1 禁用管理端

  • server.xml 中关于管理端的注释掉
[root@localhost ~]# vim /app/tools/tomcat/conf/server.xml
<!--
<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>
-->
[root@localhost ~]# systemctl restart tomcat
  • 管理端相关文件要删掉
[root@localhost ~]# rm -rf /app/tools/tomcat/webapps/*

9.1.2 降权启动

  • 监牢模式(keep in jail)
    • 让服务通过普通用户运行
  • tomcat目录所有者 改为普通用户即可
[root@localhost ~]# cat /usr/lib/systemd/system/tomcat.service 
[Unit]
Description=The tomcat web server by Apache
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
EnvironmentFile=/etc/sysconfig/tomcat
User=www
ExecStart=/app/tools/tomcat/bin/startup.sh
ExecStop=/app/tools/tomcat/bin/shutdown.sh
ExecReload=/app/tools/tomcat/bin/shutdown.sh && sleep 2 && /app/tools/tomcat/bin/startup.sh

[Install]
WantedBy=multi-user.target

[root@localhost ~]# chown -R www.www /app/tools/tomcat/
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart tomcat
[root@localhost ~]# ps -ef |grep java
www         1895       1 69 11:40 ?        00:00:16 /app/tools/jdk/bin/java -Djava.util.logging.config.file=/app/tools/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dsun.io.useCanonCaches=false -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=172.16.17.10 -Dignore.endorsed.dirs= -classpath /app/tools/tomcat/bin/bootstrap.jar:/app/tools/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/app/tools/tomcat -Dcatalina.home=/app/tools/tomcat -Djava.io.tmpdir=/app/tools/tomcat/temp org.apache.catalina.startup.Bootstrap start
root        2037    1645  0 11:40 pts/0    00:00:00 grep --color=auto java

# 配置普通用户可以重启tomcat服务(sudo)
[root@localhost ~]# visudo
www ALL=(ALL) /bin/systemctl restart tomcat

[root@localhost ~]# su - www
[www@localhost ~]$ sudo systemctl restart tomcat
[sudo] password for www: 
# 普通用户没有权限关闭tomcat
[www@localhost ~]$ sudo systemctl stop tomcat
Sorry, user www is not allowed to execute '/bin/systemctl stop tomcat' as root on localhost.localdomain.

9.1.3 文件列表访问控制

  • 类似于nginx中的autoindex,默认是关闭的
[root@localhost ~]# cat /app/tools/tomcat/conf/web.xml | grep -A1 listings\<
            <param-name>listings</param-name>
            <param-value>false</param-value>		# 此处为false就是关闭

9.1.4 版本信息隐藏

  • 隐藏报错页面的版本号信息
  • 修改conf/web.xml ,重定向403、404、以及500等错误页面
  • 或者修改应用程序目录下的WEB-INF/web.xml 下的配置,进行错误页面重定向
    • Tomcat 9默认使用JSP页面而非web.xml配置错误页面
[root@localhost ~]# cat /app/tools/tomcat/zrlog/ROOT/WEB-INF/web.xml 
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
    <!-- for sae -->
    <distributable/>
    <error-page>
        <error-code>404</error-code>
        <location>/error/404.html</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/error/500.html</location>
    </error-page>
    <filter>
        <filter-name>JFinalFilter</filter-name>
        <filter-class>com.jfinal.core.JFinalFilter</filter-class>
        <init-param>
            <param-name>configClass</param-name>
            <param-value>com.zrlog.web.config.ZrLogConfig</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>JFinalFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

9.1.5 修改响应头信息

  • 修改 server.xml 中 8080 部分
[root@localhost ~]# cat /app/tools/tomcat/conf/server.xml |grep -A2 8080
	  <Connector port="8080" protocol="HTTP/1.1"
               Server="Nginx/1.20.2"
               connectionTimeout="20000"
[root@localhost ~]# systemctl restart tomcat
[root@localhost ~]# curl -I 127.0.0.1:8080
HTTP/1.1 200 
Content-Type: text/html;charset=UTF-8
Date: Mon, 29 Dec 2025 07:18:18 GMT
Server: Nginx/1.20.2

9.1.6 访问限制

  • 根据需要可以对某些访问请求做限制
  • 类似于Nginx中的allow和deny

  • server.xml 中 Host部分内容

    • path 匹配url
<Context path="/admin" docBase="/app/tools/tomcat/zrlog/admin"
    debug="0" reloadable="false" crossContext="true">
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
    allow="123.123.123.123,123.233.233.*" deny="*.*.*.*" />
</Context>

9.2 性能优化

9.2.1 工作模式(io模型)

模式 英文 含义
bio blocking io Tomcat 7及之前,同步模型阻塞。一个线程处理一个请求,缺点:并发量高时,线程数较多,浪费资源。
nio new io Tomcat 8及以后的工作模式,异步 非阻塞。nio1(默认的)/ nio2,可以通过少量的线程处理大量的请求。
apr Apache Portable Runtime 应对高并发场景Tomcat对静态文件的处理性能。Tomcat apr也是在Tomcat上运行高并发应用的首选模式。
  • 修改为nio模式
[root@localhost ~]# cat /app/tools/tomcat/conf/server.xml |grep 8080
	  <Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
	  
[root@localhost ~]# systemctl restart tomcat

# 可以在启动日志中看到io模型
[root@localhost ~]# tail -f /app/tools/tomcat/logs/catalina.out
29-Dec-2025 15:42:41.866 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio2-8080"]

9.2.2 禁用dns逆向解析

  1. 性能优化:当enableLookups="true"时,Tomcat会对每个请求的客户端IP进行DNS反向解析,将IP地址转换为域名。这个过程需要向DNS服务器发起查询,会消耗网络资源和时间,增加请求响应延迟。
  2. 减少网络开销:DNS查询需要与DNS服务器进行网络通信,在高并发场景下会产生大量DNS查询请求,可能造成网络拥塞或DNS服务器压力过大。
  3. 避免超时风险:如果DNS服务器响应慢或不可达,会导致请求处理超时,影响服务可用性。
  4. 安全考虑:减少对外部DNS服务的依赖,降低因DNS服务异常导致的服务中断风险。
[root@localhost ~]# cat /app/tools/tomcat/conf/server.xml|grep -A1 8080
	  <Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               enableLookups="false"
[root@localhost ~]# systemctl restart tomcat

9.2.3 开启压缩功能

  • 压缩的是静态资源 html js css
  • 相当于nginx gzip on
[root@localhost ~]# cat /app/tools/tomcat/conf/server.xml | grep -A3 8080
	  <Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
               compression="on"
               compressionMinSize="2048"
               compressableMimeType="text/html,text/plain,text/css,application/javascript,application/json,application/x-font-ttf,application/x-font-otf"

[root@localhost ~]# systemctl restart tomcat
  • 查看效果
    • 其中第二个文件video-js大小是3.6kb,可以看下源文件大小是16kb,确实已经压缩
[root@localhost ~]# ll -h /app/tools/tomcat/zrlog/ROOT/assets/css/video-js.css 
-rw-r----- 1 www www 16K Jun 27  2021 /app/tools/tomcat/zrlog/ROOT/assets/css/video-js.css

9.2.4 动态选项-线程数量

  • 设置好数字,然后通过压力测试软件调试 配合监控
  • 常用压力测试工具
    • ab (http)
    • stress (系统)
    • jmeter (http/接口)
    • LoadRunner (专业压力测试工具)
maxThreads="500"					# 最大的线程数量  200-400之间
acceptCount="500"					# 当达到最大线程数量的时候 队列长度,一般与maxThreads一致
acceptorThreadCount="2"				# 队列数, 与CPU核心数保持一致,默认是1
minSpareThreads="10"				# 空闲时候最小的线程数量

9.2.5 jvm内存调整

  • jvm初始内存 推荐等于 jvm最大内存

    • 1. 避免堆内存扩容时的性能抖动

      当-Xms小于-Xmx时,JVM会根据内存使用情况动态调整堆大小。每次扩容都需要进行垃圾回收(GC)来整理内存碎片,这个过程会暂停应用线程,导致响应延迟增加。设置相同值后,JVM启动时就分配好所需内存,避免了运行时的扩容操作。

    • 2. 减少GC频率

      堆内存扩容时通常伴随Full GC,而Full GC会暂停所有应用线程,对响应时间影响较大。固定堆大小后,可以更好地预测GC行为,减少Full GC的发生。

    • 3. 提高内存利用率

      动态扩容可能导致内存碎片化,而固定堆大小让JVM可以更高效地管理内存,减少内存碎片。

    • 4. 系统稳定性提升

      避免因内存不足导致的OOM(OutOfMemoryError)风险,特别是在高并发场景下,动态扩容可能来不及响应突发的内存需求。

# 修改catalina.sh文件
JAVA_OPTS='-Xms1024m -Xmx1024m -Xloggc:/var/log/tomcat_gc.log'
# -Xms	jvm初始内存
# -Xmx	jvm最大内存
# -Xloggc	执行gc的时候,崩溃了,gc日志

文章作者: AaronXu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 AaronXu !
评论
  目录