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. 处理流程
- 请求到达Connector
- Connector解析请求,创建Request/Response对象
- 传递到Engine容器
- 根据Host配置选择虚拟主机
- 根据URL找到对应的Context
- 执行Filter链
- 调用对应的Servlet
- 返回响应
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 "%r" %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 "%r" %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 "%r" %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 "%r" %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 "%r" %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
- 从Java JDK9开始,这个工具就不自带了,可以单独下载:https://visualvm.github.io/download.html
下载并解压后,需要配置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的线程
- 导出各种统计线程、进程信息
- 与开发一起排查
- 整体排查 使用
vmstat(r cpu b io)/top/ps aux找出哪个进程的问题。 - 找出进程对应线程id
- 通过
top -Hp java进程id找出是哪个 Java 线程的问题。 - 或者使用
show_busy_java_threads.sh脚本。
- 通过
- 转换线程id为16进制 问题线程的 id 转换为 16 进制。
echo 'obase=16;1138' | bc - 找出线程的详细信息 使用
jstack显示 Java 进程信息:jstack Java进程id |grep -A 10 故障线程id过滤 Java 线程的 16 进制 id,并与开发沟通。 - 显示 JVM 信息 使用
jmap显示 Java JVM 信息:jmap -heap java进程id显示 JVM 的内存使用情况。 - JVM 内存内容导出 使用
jmap导出 JVM 内存的内容:jmap -dump:format=b,file=/root/tomcat.bin pid - 分析 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逆向解析
- 性能优化:当
enableLookups="true"时,Tomcat会对每个请求的客户端IP进行DNS反向解析,将IP地址转换为域名。这个过程需要向DNS服务器发起查询,会消耗网络资源和时间,增加请求响应延迟。 - 减少网络开销:DNS查询需要与DNS服务器进行网络通信,在高并发场景下会产生大量DNS查询请求,可能造成网络拥塞或DNS服务器压力过大。
- 避免超时风险:如果DNS服务器响应慢或不可达,会导致请求处理超时,影响服务可用性。
- 安全考虑:减少对外部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日志