Apache Tomcat 完整知识总结与使用教程
目录
- [Tomcat 简介与历史](#Tomcat 简介与历史)
- 版本选择指南
- 安装与目录结构
- 核心架构解析
- 核心组件详解
- 请求处理流程
- 配置文件详解
- [Web 应用部署](#Web 应用部署)
- [SSL/TLS 配置](#SSL/TLS 配置)
- 性能调优
- [JVM 调优](#JVM 调优)
- 集群与会话复制
- 安全加固
- 日志管理
- 类加载机制
- 虚拟主机配置
- [与 Nginx/Apache HTTPD 集成](#与 Nginx/Apache HTTPD 集成)
- 监控与管理
- 常见问题排查
- 最佳实践总结
1. Tomcat 简介与历史
1.1 什么是 Apache Tomcat
Apache Tomcat(以下简称 Tomcat)是一款由 Apache 软件基金会主导的开源 Java Servlet 容器,也是 Java Web 应用服务器中使用最为广泛的实现之一。其核心功能是实现 Jakarta EE(前身为 Java EE)中 Servlet 和 JSP(Jakarta Server Pages)规范,同时支持 WebSocket、EL 表达式语言等相关规范。
Tomcat 可以作为:
- 独立 Web 服务器:直接接收 HTTP/HTTPS 请求并处理
- Servlet/JSP 容器:配合 Apache HTTPD 或 Nginx 作为后端容器运行
- 嵌入式服务器:嵌入到 Spring Boot 等框架中使用
1.2 历史背景
| 时间节点 | 事件 |
|---|---|
| 1999 年 | Sun Microsystems 将 Servlet/JSP 参考实现贡献给 Apache 基金会,Tomcat 诞生 |
| 2005 年 | Tomcat 成为 Apache 顶级项目(TLP) |
| 2006 年 | Tomcat 5.5 发布,性能大幅提升 |
| 2011 年 | Tomcat 7.0 发布,支持 Servlet 3.0 |
| 2014 年 | Tomcat 8.0 发布,支持 Servlet 3.1 |
| 2016 年 | Tomcat 8.5 发布,成为 8.0 的改进版 |
| 2018 年 | Tomcat 9.0 发布,支持 Servlet 4.0(Java EE 8) |
| 2021 年 | Tomcat 10.0/10.1 发布,命名空间迁移至 Jakarta EE |
| 2023 年 | Tomcat 11.0 发布,支持 Servlet 6.1(Jakarta EE 11) |
1.3 Tomcat 的核心特性
- 轻量级:相比 JBoss、WebLogic 等全功能 Java EE 服务器,Tomcat 只实现 Servlet/JSP 核心规范,启动快速、资源占用低
- 开源免费:Apache License 2.0,可商业使用
- 跨平台:纯 Java 实现,支持 Windows、Linux、macOS
- 社区活跃:大量文档、论坛、第三方资源
- 高可扩展性:通过 Valve、Filter、Listener 等机制灵活扩展
- 集群支持:内置 Session 复制、集群部署能力
- 安全特性:SSL/TLS、Realm 认证、Security Manager 等
2. 版本选择指南
2.1 版本与规范对应关系
| Tomcat 版本 | Servlet 规范 | JSP 规范 | EL 规范 | WebSocket | Java 最低要求 | 状态 |
|---|---|---|---|---|---|---|
| 11.0.x | 6.1 | 4.0 | 6.0 | 2.2 | Java 17 | 当前开发版 |
| 10.1.x | 6.0 | 3.1 | 5.0 | 2.1 | Java 11 | 当前稳定版 |
| 9.0.x | 4.0 | 2.3 | 3.0 | 1.1 | Java 8 | 长期支持(至2027年) |
| 8.5.x | 3.1 | 2.3 | 3.0 | 1.1 | Java 7 | 终止支持 |
| 8.0.x | 3.1 | 2.3 | 3.0 | 1.1 | Java 7 | EOL |
| 7.0.x | 3.0 | 2.2 | 2.2 | 1.1 | Java 6 | EOL |
重要提示 :Tomcat 10+ 将包名从
javax.*迁移到了jakarta.*,与 Jakarta EE 9+ 对齐。若您的应用依赖javax.servlet.*,请使用 Tomcat 9.x。
2.2 版本选择建议
- 新项目 + Spring Boot 3.x:推荐 Tomcat 10.1(Spring Boot 3.x 默认使用)
- 存量 Java EE 8 项目 :推荐 Tomcat 9.0(最后一个支持
javax.*的主要版本) - 企业级长期支持需求:使用 Tomcat 9.x(Apache 承诺超 10 年支持)
- 最新技术探索:使用 Tomcat 11.0
3. 安装与目录结构
3.1 环境准备
安装 Tomcat 前,需先安装 JDK 并配置 JAVA_HOME 环境变量。
bash
# 检查 Java 版本
java -version
# 设置 JAVA_HOME(Linux/macOS)
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
export PATH=$JAVA_HOME/bin:$PATH
3.2 下载安装(Linux)
bash
# 1. 下载 Tomcat(以 10.1 为例)
wget https://downloads.apache.org/tomcat/tomcat-10/v10.1.x/bin/apache-tomcat-10.1.x.tar.gz
# 2. 解压
tar -zxvf apache-tomcat-10.1.x.tar.gz -C /opt/
# 3. 创建软链接(便于版本管理)
ln -s /opt/apache-tomcat-10.1.x /opt/tomcat
# 4. 设置执行权限
chmod +x /opt/tomcat/bin/*.sh
# 5. 配置环境变量
export CATALINA_HOME=/opt/tomcat
export PATH=$CATALINA_HOME/bin:$PATH
3.3 安装(Windows)
- 从官网下载
.zip或.exe安装包 - 解压到目标目录(如
C:\tomcat) - 运行
bin\startup.bat启动,或通过.exe安装为 Windows 服务
3.4 启动与停止
bash
# 启动
$CATALINA_HOME/bin/startup.sh # Linux/macOS
%CATALINA_HOME%\bin\startup.bat # Windows
# 停止
$CATALINA_HOME/bin/shutdown.sh # Linux/macOS
%CATALINA_HOME%\bin\shutdown.bat # Windows
# 带安全管理器启动
$CATALINA_HOME/bin/startup.sh -security
# 以前台方式运行(便于调试)
$CATALINA_HOME/bin/catalina.sh run
访问 http://localhost:8080 验证是否成功启动。
3.5 目录结构详解
$CATALINA_HOME/
├── bin/ # 可执行脚本
│ ├── startup.sh # 启动脚本
│ ├── shutdown.sh # 停止脚本
│ ├── catalina.sh # 核心控制脚本
│ ├── setenv.sh # 自定义环境变量(需手动创建)
│ └── bootstrap.jar # 引导 JAR
│
├── conf/ # 配置文件目录(核心)
│ ├── server.xml # 主配置文件(服务器、连接器、虚拟主机)
│ ├── web.xml # 全局默认 Web 应用配置
│ ├── context.xml # 全局 Context 配置(JNDI、Session等)
│ ├── tomcat-users.xml # 用户、角色管理(Manager/Admin)
│ ├── logging.properties # 日志配置
│ └── catalina.policy # 安全策略文件
│
├── lib/ # 共享类库(所有 Web 应用可访问)
│ ├── catalina.jar # Catalina 核心
│ ├── jasper.jar # JSP 引擎
│ └── ...
│
├── logs/ # 日志输出目录
│ ├── catalina.out # 主日志(标准输出)
│ ├── catalina.YYYY-MM-DD.log # Catalina 日志
│ ├── localhost.YYYY-MM-DD.log # localhost 日志
│ ├── manager.YYYY-MM-DD.log # Manager 应用日志
│ └── localhost_access_log.YYYY-MM-DD.txt # 访问日志
│
├── webapps/ # Web 应用部署目录(默认)
│ ├── ROOT/ # 根应用(访问路径:/)
│ ├── manager/ # 管理控制台(访问路径:/manager)
│ ├── host-manager/ # 虚拟主机管理
│ └── examples/ # 示例应用(生产环境应删除)
│
├── work/ # 运行时工作目录(JSP 编译输出等)
│ └── Catalina/
│ └── localhost/
│
└── temp/ # 临时文件目录
最佳实践 :生产环境建议分离
CATALINA_HOME(安装目录)和CATALINA_BASE(实例目录),实现一套 Tomcat 二进制文件运行多个实例。
4. 核心架构解析
4.1 整体架构图
Server(整个 Tomcat 容器)
└── Service(服务)
├── Connector(HTTP 连接器,端口 8080)
├── Connector(HTTPS 连接器,端口 8443)
├── Connector(AJP 连接器,端口 8009)
└── Engine(Catalina 引擎)
├── Host(虚拟主机:localhost)
│ ├── Context(Web 应用:/myapp)
│ │ ├── Wrapper(Servlet:MyServlet)
│ │ └── Wrapper(Servlet:AnotherServlet)
│ └── Context(Web 应用:/admin)
└── Host(虚拟主机:www.example.com)
└── Context(Web 应用:/)
4.2 核心模块
| 模块名 | 职责 |
|---|---|
| Catalina | Servlet 容器核心,管理所有容器组件的生命周期 |
| Coyote | HTTP/AJP 连接器,负责网络通信(接收、解析请求,发送响应) |
| Jasper | JSP 引擎,将 .jsp 文件编译为 Servlet 并执行 |
| Tribes | 集群通信框架,用于节点发现和数据复制 |
| Juli | 日志框架,基于 java.util.logging |
| el | EL(Expression Language)表达式解析引擎 |
5. 核心组件详解
5.1 Server
Server 代表整个 Tomcat 实例,是所有其他组件的顶级容器。
xml
<Server port="8005" shutdown="SHUTDOWN">
<!-- 属性说明 -->
<!-- port: 关闭监听端口;shutdown: 关闭命令字符串 -->
<!-- 安全建议:将 port 改为随机端口或 -1,避免被远程关闭 -->
</Server>
5.2 Service
Service 将一个或多个 Connector 绑定到单个 Engine。通常一个 Server 只有一个 Service。
xml
<Service name="Catalina">
<!-- 包含 Connector 和 Engine -->
</Service>
5.3 Connector(连接器)
连接器是 Tomcat 与外部客户端通信的入口。
HTTP/1.1 Connector(NIO)
xml
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="200"
minSpareThreads="10"
acceptCount="100"
enableLookups="false"
compression="on"
compressableMimeType="text/html,text/xml,text/plain,text/css,application/json"
URIEncoding="UTF-8" />
HTTP/2 + NIO2
xml
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
... />
AJP Connector(与 Apache HTTPD 集成)
xml
<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443"
secretRequired="false" />
主要参数说明
| 参数 | 默认值 | 说明 |
|---|---|---|
port |
- | 监听端口 |
maxThreads |
200 | 最大工作线程数 |
minSpareThreads |
10 | 最小空闲线程数 |
maxConnections |
10000(NIO) | 最大并发连接数 |
acceptCount |
100 | 等待队列最大长度 |
connectionTimeout |
20000 | 连接超时(毫秒) |
keepAliveTimeout |
- | Keep-Alive 超时(毫秒) |
maxKeepAliveRequests |
100 | 单连接最大请求数 |
enableLookups |
false | 是否做 DNS 反查(建议 false) |
compression |
off | 是否启用 GZIP 压缩 |
URIEncoding |
UTF-8 | URI 编码 |
5.4 Engine(引擎)
Engine 是请求处理的核心流水线,接收来自所有 Connector 的请求,分发给相应的 Host。
xml
<Engine name="Catalina" defaultHost="localhost">
<!-- defaultHost: 默认虚拟主机名,当请求 Host 匹配不到时使用 -->
<!-- jvmRoute: 集群环境中标识节点,与负载均衡器配合 -->
</Engine>
5.5 Host(虚拟主机)
Host 将域名映射到 Tomcat 上的应用。
xml
<Host name="localhost"
appBase="webapps"
unpackWARs="true"
autoDeploy="true"
deployOnStartup="true">
<!-- 别名 -->
<Alias>www.example.com</Alias>
<!-- 访问日志 Valve -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
| 参数 | 说明 |
|---|---|
name |
虚拟主机名(对应请求 Host 头) |
appBase |
Web 应用部署目录(相对于 CATALINA_HOME) |
unpackWARs |
是否自动解压 WAR |
autoDeploy |
是否自动检测并部署新 WAR/目录 |
deployOnStartup |
启动时自动部署 |
5.6 Context(应用上下文)
Context 代表一个 Web 应用,可在多处配置:
$CATALINA_HOME/conf/server.xml中的<Host>内$CATALINA_HOME/conf/[enginename]/[hostname]/[appname].xml- Web 应用的
META-INF/context.xml
xml
<Context path="/myapp"
docBase="/opt/apps/myapp"
reloadable="true"
crossContext="false"
privileged="false">
<!-- JNDI 数据源 -->
<Resource name="jdbc/myDB"
auth="Container"
type="javax.sql.DataSource"
maxTotal="50"
maxIdle="10"
minIdle="5"
maxWaitMillis="10000"
username="dbuser"
password="dbpass"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mydb?useSSL=false" />
</Context>
5.7 Wrapper(Servlet 包装器)
Wrapper 是 Tomcat 中对单个 Servlet 的包装,管理 Servlet 的初始化、执行和销毁生命周期。开发者通常不需要直接配置 Wrapper,而是通过 web.xml 声明 Servlet。
6. 请求处理流程
6.1 完整处理链
客户端发起 HTTP 请求
↓
Coyote Connector(监听端口,接收 TCP 连接)
↓
HTTP 协议解析(解析 Request Line、Headers、Body)
↓
创建 Request / Response 对象
↓
Engine.pipeline.invoke() → 经过 Engine 级 Valve 链
↓
Host.pipeline.invoke() → 经过 Host 级 Valve 链(含 AccessLogValve)
↓
Context.pipeline.invoke() → 经过 Context 级 Valve 链
↓
应用级 Filter 链(web.xml 中的 Filter)
↓
Wrapper.pipeline.invoke() → 经过 Wrapper 级 Valve 链
↓
Servlet.service() → doGet() / doPost() ...
↓
JSP Engine(Jasper):如需渲染 JSP,编译为 Servlet 并执行
↓
Response 写回 → Coyote 序列化为 HTTP 响应 → 发送给客户端
6.2 Valve 管道机制
Valve 是 Tomcat 中的拦截器,形成流水线(Pipeline),类似 Servlet Filter 但作用于容器层次。
常用内置 Valve:
| Valve 类名 | 功能 |
|---|---|
AccessLogValve |
记录访问日志 |
RemoteAddrValve |
按 IP 控制访问 |
RemoteHostValve |
按主机名控制访问 |
RequestDumperValve |
打印请求详情(调试用) |
SemaphoreValve |
限流(最大并发请求数) |
ReplicationValve |
集群 Session 复制触发 |
7. 配置文件详解
7.1 server.xml 完整示例
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" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<!-- 全局 JNDI 资源 -->
<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">
<!-- HTTP Connector -->
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="500"
minSpareThreads="50"
acceptCount="200"
enableLookups="false"
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/plain,text/css,application/json,application/javascript"
URIEncoding="UTF-8"
redirectPort="8443" />
<!-- HTTPS Connector -->
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="conf/keystore.jks"
certificateKeystorePassword="changeit"
type="RSA" />
</SSLHostConfig>
</Connector>
<!-- AJP Connector(可选) -->
<!--
<Connector protocol="AJP/1.3"
address="127.0.0.1"
port="8009"
redirectPort="8443" />
-->
<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 %D" />
</Host>
</Engine>
</Service>
</Server>
7.2 web.xml(全局默认)
conf/web.xml 定义了适用于所有 Web 应用的默认 Servlet 和 MIME 类型映射:
xml
<!-- DefaultServlet:处理静态资源请求 -->
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value> <!-- 生产环境禁用目录列表 -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- JspServlet:处理 JSP 请求 -->
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
7.3 context.xml(全局 Context 配置)
xml
<Context>
<!-- 禁止 Web 应用覆盖全局配置 -->
<!-- <WatchedResource>WEB-INF/web.xml</WatchedResource> -->
<!-- CookieProcessor:配置 SameSite 等安全属性 -->
<CookieProcessor sameSiteCookies="strict" />
<!-- Manager:Session 管理 -->
<Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\.(?:Linked)?HashMap" />
</Context>
7.4 tomcat-users.xml
xml
<tomcat-users>
<!-- 定义角色 -->
<role rolename="manager-gui" />
<role rolename="manager-script" />
<role rolename="manager-jmx" />
<role rolename="admin-gui" />
<!-- 定义用户 -->
<user username="admin"
password="yourStrongPassword"
roles="manager-gui,admin-gui" />
<user username="deployer"
password="anotherStrongPassword"
roles="manager-script" />
</tomcat-users>
8. Web 应用部署
8.1 WAR 包部署
方式一:热部署(推荐开发环境)
bash
# 将 WAR 包复制到 webapps 目录,Tomcat 会自动解压并部署
cp myapp.war $CATALINA_HOME/webapps/
方式二:Manager 管理界面
访问 http://localhost:8080/manager/html,使用具有 manager-gui 角色的账号登录,通过界面上传 WAR 包。
方式三:Manager HTTP API
bash
# 部署
curl -u admin:password http://localhost:8080/manager/text/deploy?path=/myapp \
--upload-file myapp.war
# 卸载
curl -u admin:password http://localhost:8080/manager/text/undeploy?path=/myapp
# 重载
curl -u admin:password http://localhost:8080/manager/text/reload?path=/myapp
# 列出所有应用
curl -u admin:password http://localhost:8080/manager/text/list
方式四:Context 描述符
在 $CATALINA_HOME/conf/Catalina/localhost/ 目录下创建 myapp.xml:
xml
<Context docBase="/opt/myapp" reloadable="false" />
8.2 Web 应用目录结构
myapp/
├── index.html # 静态资源
├── WEB-INF/
│ ├── web.xml # Web 应用部署描述符(必须)
│ ├── classes/ # 编译后的 .class 文件
│ │ └── com/example/MyServlet.class
│ └── lib/ # 应用依赖的 JAR 包
│ └── mysql-connector.jar
└── META-INF/
└── context.xml # 应用级 Context 配置(可选)
8.3 web.xml 基础配置
xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0">
<display-name>My Application</display-name>
<!-- Servlet 定义 -->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.example.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!-- Filter -->
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Session 超时(分钟) -->
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<http-only>true</http-only>
<secure>true</secure>
</cookie-config>
</session-config>
<!-- 欢迎页 -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 错误页面 -->
<error-page>
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error/500.jsp</location>
</error-page>
</web-app>
9. SSL/TLS 配置
9.1 生成自签名证书(测试用)
bash
# 使用 JDK keytool 生成 RSA 2048 密钥对和自签名证书
keytool -genkeypair \
-alias tomcat \
-keyalg RSA \
-keysize 2048 \
-validity 3650 \
-keystore $CATALINA_HOME/conf/keystore.jks \
-storepass changeit \
-keypass changeit \
-dname "CN=localhost, OU=Dev, O=MyOrg, L=Beijing, ST=Beijing, C=CN"
9.2 导入 CA 签发证书(生产用)
bash
# 1. 生成 CSR
keytool -certreq -alias tomcat -keystore keystore.jks -file tomcat.csr
# 2. 将 CSR 提交给 CA,获取签发证书(cert.crt)和 CA 链(ca-bundle.crt)
# 3. 导入 CA 链
keytool -import -alias root -keystore keystore.jks -trustcacerts -file ca-bundle.crt
# 4. 导入签发证书
keytool -import -alias tomcat -keystore keystore.jks -file cert.crt
也可直接使用 Let's Encrypt 的 PEM 格式证书(转换为 PKCS12):
bash
openssl pkcs12 -export \
-in fullchain.pem \
-inkey privkey.pem \
-out keystore.p12 \
-name tomcat \
-password pass:changeit
9.3 server.xml HTTPS Connector 配置
方式一:JKS 格式
xml
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="conf/keystore.jks"
certificateKeystorePassword="changeit"
type="RSA" />
</SSLHostConfig>
</Connector>
方式二:PKCS12 格式(推荐)
xml
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true">
<SSLHostConfig protocols="TLSv1.2+TLSv1.3"
ciphers="TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384">
<Certificate certificateKeystoreFile="conf/keystore.p12"
certificateKeystorePassword="changeit"
certificateKeystoreType="PKCS12"
type="RSA" />
</SSLHostConfig>
</Connector>
9.4 强制 HTTP 跳转到 HTTPS
在 web.xml 中添加安全约束(作用于所有请求):
xml
<security-constraint>
<web-resource-collection>
<web-resource-name>Entire Application</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
10. 性能调优
10.1 连接器(Connector)调优
xml
<Connector port="8080"
protocol="org.apache.coyote.http11.Http11NioProtocol"
<!-- 线程池 -->
maxThreads="500" <!-- 最大工作线程,建议:CPU核心数 × 50~100 -->
minSpareThreads="50" <!-- 最小保活线程 -->
<!-- 连接队列 -->
acceptCount="200" <!-- OS 等待队列长度,默认 100 不够用 -->
maxConnections="10000" <!-- NIO 模式最大连接数 -->
<!-- 超时 -->
connectionTimeout="20000" <!-- 连接建立超时 20s -->
keepAliveTimeout="15000" <!-- Keep-Alive 超时 15s -->
maxKeepAliveRequests="100" <!-- 单连接最大复用请求次数 -->
<!-- 性能开关 -->
enableLookups="false" <!-- 禁用 DNS 反查(重要!) -->
disableUploadTimeout="true"
<!-- 压缩 -->
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/plain,text/css,
application/json,application/javascript"
<!-- 编码 -->
URIEncoding="UTF-8"
useBodyEncodingForURI="true" />
10.2 使用 Executor 共享线程池
当有多个 Connector 时,可以共享线程池:
xml
<!-- 定义线程池 -->
<Executor name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="500"
minSpareThreads="50"
maxIdleTime="60000"
maxQueueSize="Integer.MAX_VALUE" />
<!-- Connector 引用共享线程池 -->
<Connector port="8080"
protocol="HTTP/1.1"
executor="tomcatThreadPool"
connectionTimeout="20000"
redirectPort="8443" />
10.3 压缩配置(Compression)
启用 GZIP 压缩可显著减少文本类响应的传输大小(通常减少 70%~90%):
xml
<Connector ...
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/plain,text/css,
application/json,application/javascript" />
10.4 静态资源缓存
在全局 web.xml 中配置 DefaultServlet 的缓存策略:
xml
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cacheMaxSize</param-name>
<param-value>100000</param-value> <!-- KB -->
</init-param>
<init-param>
<param-name>cacheTtl</param-name>
<param-value>5000</param-value> <!-- 毫秒 -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
10.5 数据库连接池(JNDI DataSource)
避免每次请求都新建数据库连接:
xml
<!-- context.xml -->
<Resource name="jdbc/myDB"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
maxActive="100" <!-- 最大活跃连接 -->
maxIdle="30" <!-- 最大空闲连接 -->
minIdle="10" <!-- 最小空闲连接 -->
maxWait="10000" <!-- 等待连接超时(毫秒) -->
initialSize="10" <!-- 初始连接数 -->
validationQuery="SELECT 1"
testOnBorrow="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="30000"
minEvictableIdleTimeMillis="60000"
username="user"
password="pass"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mydb?useSSL=true&serverTimezone=UTC" />
11. JVM 调优
11.1 setenv.sh 配置
在 $CATALINA_HOME/bin/ 下创建 setenv.sh(Linux/macOS)或 setenv.bat(Windows),统一管理 JVM 参数:
bash
#!/bin/bash
# $CATALINA_HOME/bin/setenv.sh
# 堆内存设置(Xms 和 Xmx 设置相同值,避免动态扩缩)
export CATALINA_OPTS="-server \
-Xms2g \
-Xmx2g \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-Xss512k \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:G1HeapRegionSize=16m \
-XX:+UseStringDeduplication \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/log/tomcat/heap-dump.hprof \
-XX:ErrorFile=/var/log/tomcat/hs_err.log \
-Djava.awt.headless=true \
-Dfile.encoding=UTF-8 \
-Djava.security.egd=file:/dev/./urandom"
11.2 JVM 参数详解
| 参数 | 说明 | 推荐值 |
|---|---|---|
-Xms |
初始堆大小 | 与 -Xmx 相同 |
-Xmx |
最大堆大小 | 物理内存的 50%~70% |
-XX:MetaspaceSize |
元空间初始大小 | 256m |
-XX:MaxMetaspaceSize |
元空间最大值 | 512m |
-Xss |
线程栈大小 | 512k |
-XX:+UseG1GC |
使用 G1 垃圾收集器 | Java 9+ 推荐 |
-XX:MaxGCPauseMillis |
G1 最大停顿目标 | 200ms |
-XX:+HeapDumpOnOutOfMemoryError |
OOM 时生成堆转储 | 生产环境必须启用 |
-server |
使用服务端 JIT 编译器 | 生产环境必须启用 |
11.3 垃圾收集器选择
| GC | 适用场景 | 参数 |
|---|---|---|
| G1 GC | Java 9+ 通用场景(推荐) | -XX:+UseG1GC |
| ZGC | 超低延迟(Java 15+ 生产可用) | -XX:+UseZGC |
| Shenandoah | 超低延迟(RedHat 主导) | -XX:+UseShenandoahGC |
| Parallel GC | 高吞吐批处理 | -XX:+UseParallelGC |
12. 集群与会话复制
12.1 会话复制原理
Tomcat 内置的集群会话复制基于**组播(Multicast)**进行节点发现,基于 TCP 单播进行数据复制。
两种 Session 复制策略:
- DeltaManager(默认):全量复制到所有节点。适合小集群(≤4节点),节点需部署相同应用。
- BackupManager:仅复制到一个备份节点。适合大集群,支持异构部署。
12.2 集群配置(server.xml)
xml
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<!-- Session 管理器 -->
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true" />
<!-- Channel(通信层) -->
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<!-- 成员管理(组播发现) -->
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000" />
<!-- 数据接收 -->
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6" />
<!-- 数据发送 -->
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
</Sender>
<!-- 拦截器 -->
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector" />
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor" />
</Channel>
<!-- 会话复制 Valve -->
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter="" />
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve" />
<!-- 应用部署监听器 -->
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false" />
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener" />
</Cluster>
12.3 应用端配置
在 Web 应用的 web.xml 中添加 <distributable/>:
xml
<web-app ...>
<distributable/>
<!-- ... -->
</web-app>
注意 :所有存储在 Session 中的对象必须实现
java.io.Serializable接口。
12.4 与负载均衡器集成
配置 Nginx 负载均衡(粘性会话):
nginx
upstream tomcat_cluster {
ip_hash; # 基于 IP 的粘性会话
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
server {
listen 80;
location / {
proxy_pass http://tomcat_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
13. 安全加固
13.1 系统级安全
bash
# 1. 创建专用 Tomcat 运行用户(禁止 root 运行)
useradd -r -s /bin/false tomcat
chown -R tomcat:tomcat $CATALINA_HOME
# 2. 设置正确文件权限
chmod 750 $CATALINA_HOME/conf
chmod 640 $CATALINA_HOME/conf/*
chmod 750 $CATALINA_HOME/logs
chmod 750 $CATALINA_HOME/work
chmod 750 $CATALINA_HOME/temp
13.2 隐藏服务器信息
修改 conf/server.xml 隐藏 Server 头:
xml
<Connector port="8080" protocol="HTTP/1.1"
Server=" " <!-- 空格,清空 Server 头 -->
... />
自定义错误页面(防止堆栈信息泄露):
xml
<!-- web.xml -->
<error-page>
<error-code>404</error-code>
<location>/custom404.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/custom500.html</location>
</error-page>
修改 lib/catalina.jar 中的 ServerInfo.properties(可选):
bash
cd $CATALINA_HOME/lib
jar xf catalina.jar org/apache/catalina/util/ServerInfo.properties
# 编辑 ServerInfo.properties,将 server.info 改为空白
jar uf catalina.jar org/apache/catalina/util/ServerInfo.properties
13.3 删除默认应用
bash
# 生产环境必须删除以下默认应用
rm -rf $CATALINA_HOME/webapps/ROOT
rm -rf $CATALINA_HOME/webapps/examples
rm -rf $CATALINA_HOME/webapps/docs
# manager 和 host-manager 保留但需严格限制访问
13.4 安全关闭端口
xml
<!-- server.xml 中将 shutdown 端口改为 -1 或随机端口 -->
<Server port="-1" shutdown="SHUTDOWN">
<!-- 如需保留,改为随机命令字 -->
<Server port="8005" shutdown="SomeRandomString_xK9m2q">
13.5 配置 IP 访问限制(Valve)
xml
<!-- 只允许本地访问 Manager 应用 -->
<!-- conf/Catalina/localhost/manager.xml -->
<Context antiResourceLocking="false" privileged="true">
<CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor"
sameSiteCookies="strict" />
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
<Manager sessionAttributeValueClassNameFilter="..."/>
</Context>
13.6 启用安全管理器
bash
# 以安全管理器模式启动(限制 Web 应用的系统调用权限)
$CATALINA_HOME/bin/startup.sh -security
13.7 安全 HTTP 响应头
在 web.xml 中添加过滤器:
xml
<!-- HTTP 安全头过滤器(Tomcat 内置) -->
<filter>
<filter-name>httpHeaderSecurity</filter-name>
<filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
<init-param>
<param-name>antiClickJackingEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>antiClickJackingOption</param-name>
<param-value>SAMEORIGIN</param-value>
</init-param>
<init-param>
<param-name>xssProtectionEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>hstsEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>hstsMaxAgeSeconds</param-name>
<param-value>31536000</param-value>
</init-param>
<init-param>
<param-name>blockContentTypeSniffingEnabled</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>httpHeaderSecurity</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
13.8 Realm 认证配置
xml
<!-- server.xml:使用 LockOutRealm 防止暴力破解 -->
<Realm className="org.apache.catalina.realm.LockOutRealm"
failureCount="5" <!-- 失败5次后锁定 -->
lockOutTime="300"> <!-- 锁定 300 秒 -->
<!-- 基于数据库的认证 -->
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/myDB"
userTable="users"
userNameCol="username"
userCredCol="password"
userRoleTable="user_roles"
roleNameCol="role_name" />
</Realm>
13.9 SSL/TLS 强化
xml
<SSLHostConfig
protocols="TLSv1.2+TLSv1.3"
ciphers="TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
honorCipherOrder="true"
disableSessionTickets="true">
安全建议:禁用 SSLv3、TLS 1.0、TLS 1.1;仅启用 TLS 1.2 和 TLS 1.3。
14. 日志管理
14.1 日志文件说明
| 文件 | 说明 |
|---|---|
catalina.out |
JVM 标准输出/错误,所有内容都会写入此文件 |
catalina.YYYY-MM-DD.log |
Catalina 内部日志(通过 Juli) |
localhost.YYYY-MM-DD.log |
应用相关日志 |
manager.YYYY-MM-DD.log |
Manager 应用日志 |
localhost_access_log.txt |
HTTP 访问日志(AccessLogValve) |
14.2 logging.properties 配置
properties
# conf/logging.properties
# 全局日志级别
handlers = 1catalina.org.apache.juli.AsyncFileHandler, \
2localhost.org.apache.juli.AsyncFileHandler, \
3manager.org.apache.juli.AsyncFileHandler, \
java.util.logging.ConsoleHandler
.level = INFO
############################################################
# Handler specific properties.
############################################################
# Catalina 处理器
1catalina.org.apache.juli.AsyncFileHandler.level = FINE
1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina.
1catalina.org.apache.juli.AsyncFileHandler.suffix = .log
1catalina.org.apache.juli.AsyncFileHandler.maxDays = 30 # 保留30天日志
1catalina.org.apache.juli.AsyncFileHandler.encoding = UTF-8
# localhost 处理器
2localhost.org.apache.juli.AsyncFileHandler.level = FINE
2localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost.
2localhost.org.apache.juli.AsyncFileHandler.suffix = .log
2localhost.org.apache.juli.AsyncFileHandler.maxDays = 30
2localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8
# 控制台处理器
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
java.util.logging.ConsoleHandler.encoding = UTF-8
############################################################
# Facility specific properties.
############################################################
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.AsyncFileHandler
14.3 访问日志格式(AccessLogValve)
xml
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="access_log"
suffix=".txt"
rotatable="true"
fileDateFormat="yyyy-MM-dd"
pattern="%h %l %u %t "%r" %s %b %D %{Referer}i %{User-Agent}i"
resolveHosts="false"
buffered="true" />
常用 Pattern 变量说明:
| 变量 | 说明 |
|---|---|
%h |
远端主机名或 IP |
%l |
远端逻辑用户名(通常为 -) |
%u |
认证用户名 |
%t |
请求时间 |
%r |
请求首行(方法、URI、协议) |
%s |
HTTP 状态码 |
%b |
响应字节数(不含头部) |
%D |
请求处理时间(毫秒) |
%{xxx}i |
请求头字段 |
%{xxx}o |
响应头字段 |
14.4 集成 Log4j2 / SLF4J
在应用的 WEB-INF/lib 中引入相应依赖,并在 WEB-INF/classes 中放置配置文件(log4j2.xml 或 logback.xml)。Tomcat 本身的日志(Juli)与应用日志框架相互独立。
15. 类加载机制
15.1 类加载层次结构
Bootstrap ClassLoader(JVM 内置)
↓
Extension/Platform ClassLoader(JDK 扩展类库)
↓
Application/System ClassLoader($CLASSPATH)
↓
Common ClassLoader($CATALINA_HOME/lib)
↓ ↘
Webapp ClassLoader Webapp ClassLoader
(WEB-INF/classes, (WEB-INF/classes,
WEB-INF/lib) WEB-INF/lib)
15.2 类加载顺序
Tomcat 的 Webapp ClassLoader 采用亲子委托倒置策略(与标准 Java 相反):
- Bootstrap + Extension ClassLoader(JVM 核心类)
WEB-INF/classes(应用自身类)WEB-INF/lib/*.jar(应用依赖)- Common ClassLoader(
$CATALINA_HOME/lib)
这意味着应用可以使用与 Tomcat 内部不同版本的库(如 Log4j)而不发生冲突。
15.3 类加载问题排查
bash
# 开启类加载详细日志
-verbose:class
# 或在 logging.properties 中
org.apache.catalina.loader.WebappClassLoader.level = DEBUG
常见问题:
- NoClassDefFoundError / ClassNotFoundException :检查 JAR 是否在
WEB-INF/lib中 - ClassCastException(同类不同加载器) :避免在
lib/和WEB-INF/lib/中放置相同 JAR - 内存泄漏(PermGen/Metaspace):确保应用关闭时正确注销 JDBC 驱动和线程
16. 虚拟主机配置
16.1 多域名配置
xml
<!-- server.xml -->
<Engine name="Catalina" defaultHost="www.siteA.com">
<!-- 站点 A -->
<Host name="www.siteA.com" appBase="/var/www/siteA" unpackWARs="true" autoDeploy="false">
<Alias>siteA.com</Alias>
<Context path="" docBase="ROOT" />
</Host>
<!-- 站点 B -->
<Host name="www.siteB.com" appBase="/var/www/siteB" unpackWARs="true" autoDeploy="false">
<Alias>siteB.com</Alias>
<Context path="" docBase="ROOT" />
</Host>
</Engine>
16.2 SNI(多域名 SSL)
Tomcat 8.5+ 支持 SNI,允许一个 HTTPS 连接器绑定多个证书:
xml
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
SSLEnabled="true" maxThreads="150">
<!-- 站点 A 的证书 -->
<SSLHostConfig hostName="www.siteA.com">
<Certificate certificateKeystoreFile="conf/siteA.p12" ... />
</SSLHostConfig>
<!-- 站点 B 的证书 -->
<SSLHostConfig hostName="www.siteB.com">
<Certificate certificateKeystoreFile="conf/siteB.p12" ... />
</SSLHostConfig>
</Connector>
17. 与 Nginx/Apache HTTPD 集成
17.1 Nginx 反向代理配置
nginx
# /etc/nginx/conf.d/tomcat.conf
upstream tomcat_backend {
server 127.0.0.1:8080;
keepalive 32;
}
server {
listen 80;
server_name www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/ssl/certs/example.crt;
ssl_certificate_key /etc/ssl/private/example.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 代理配置
location / {
proxy_pass http://tomcat_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
}
# 静态资源直接由 Nginx 处理
location ~* \.(html|css|js|png|jpg|gif|ico|woff|woff2)$ {
root /var/www/myapp;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
在 Tomcat 的 server.xml 中启用 RemoteIpValve,正确识别客户端真实 IP:
xml
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="X-Forwarded-For"
protocolHeader="X-Forwarded-Proto"
protocolHeaderHttpsValue="https" />
17.2 Apache HTTPD + mod_jk
apache
# httpd.conf 或 workers.properties
# workers.properties
worker.list=worker1
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
# httpd.conf / virtualhost
<VirtualHost *:80>
ServerName www.example.com
JkMount /* worker1
JkUnMount /static/* worker1 # 静态资源不转发
</VirtualHost>
17.3 对比:Nginx vs Apache HTTPD 反代
| 维度 | Nginx | Apache HTTPD mod_proxy |
|---|---|---|
| 性能 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 配置复杂度 | 简单 | 复杂 |
| 静态资源处理 | 极强 | 强 |
| 动态模块支持 | 较少 | 丰富 |
| 协议支持 | HTTP/1.1、HTTP/2、HTTP/3 | HTTP/1.1、HTTP/2 |
18. 监控与管理
18.1 Manager Web 应用
访问 http://localhost:8080/manager/html,需要 manager-gui 角色。
功能包括:
- 查看已部署应用列表及状态
- 部署/卸载/重载/停止/启动应用
- 查看 Session 数量
- 查看服务器信息(JVM、OS)
18.2 JMX 远程监控
bash
# setenv.sh 中配置 JMX
export CATALINA_OPTS="$CATALINA_OPTS \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=9090 \
-Dcom.sun.management.jmxremote.rmi.port=9091 \
-Djava.rmi.server.hostname=192.168.1.10 \
-Dcom.sun.management.jmxremote.authenticate=true \
-Dcom.sun.management.jmxremote.password.file=/etc/tomcat/jmxremote.password \
-Dcom.sun.management.jmxremote.access.file=/etc/tomcat/jmxremote.access \
-Dcom.sun.management.jmxremote.ssl=false"
然后用 JConsole 或 VisualVM 连接 service:jmx:rmi:///jndi/rmi://192.168.1.10:9090/jmxrmi。
18.3 Prometheus + Grafana 监控
使用 jmx_prometheus_javaagent 将 JMX 指标暴露为 Prometheus 格式:
bash
# setenv.sh
export CATALINA_OPTS="$CATALINA_OPTS \
-javaagent:/opt/jmx_prometheus_javaagent-0.20.0.jar=8888:/opt/jmx-config.yaml"
yaml
# jmx-config.yaml
---
startDelaySeconds: 0
ssl: false
lowercaseOutputName: false
rules:
- pattern: 'Catalina<type=ThreadPool, name="(.*)">'
name: tomcat_threadpool_$1
labels:
name: "$1"
18.4 关键监控指标
| 指标 | 说明 | 告警建议 |
|---|---|---|
currentThreadCount |
当前线程数 | > maxThreads × 80% 告警 |
currentThreadsBusy |
活跃线程数 | 持续 = maxThreads 告警 |
maxThreads |
最大线程数 | 参考值 |
requestCount |
请求总数 | 用于计算 QPS |
errorCount |
错误请求数 | > 1% 告警 |
processingTime |
累计处理时间 | 用于计算平均响应时间 |
| JVM Heap Used | 堆内存使用量 | > 80% 告警 |
| GC Pause Time | GC 停顿时间 | Full GC > 1s 告警 |
19. 常见问题排查
19.1 启动失败
问题:Address already in use: 8080
bash
# 查找占用端口的进程
lsof -i :8080 # Linux/macOS
netstat -ano | findstr :8080 # Windows
# 杀死进程或修改 server.xml 端口
问题:JAVA_HOME not set
bash
# 检查环境变量
echo $JAVA_HOME
which java
# 确保 setenv.sh 中设置正确
问题:OutOfMemoryError: Java heap space
bash
# 增大堆内存
export CATALINA_OPTS="-Xms1g -Xmx2g"
19.2 应用部署失败
问题:WAR 已上传但未部署
- 检查
logs/catalina.out中的异常信息 - 确认
autoDeploy="true"且deployOnStartup="true" - 检查 WAR 包是否损坏:
jar tf myapp.war
问题:Context path conflict
- 确保没有多个应用配置了相同的
path - 删除
work/目录下对应的编译缓存
19.3 性能问题
问题:响应变慢
- 查看线程状态:
jstack <pid>或通过 JMX 查看 - 检查是否有大量线程处于 BLOCKED 状态(数据库连接池耗尽)
- 检查 GC 日志,是否频繁发生 Full GC
- 确认
enableLookups=false(DNS 反查会严重拖慢请求)
问题:内存持续增长(内存泄漏)
bash
# 生成堆转储
jmap -dump:format=b,file=heap.hprof <pid>
# 或通过 Manager 接口
curl -u admin:pass http://localhost:8080/manager/text/jnlp
# 用 Eclipse MAT、VisualVM、JProfiler 分析
19.4 连接问题
问题:Connection refused
- 检查 Tomcat 是否正常运行:
ps aux | grep tomcat - 检查防火墙规则:
iptables -L、firewall-cmd --list-all - 确认 Connector 配置的端口正确
问题:Session 丢失(集群环境)
- 确保 Session 中的对象实现了
Serializable - 检查
web.xml中是否有<distributable/> - 检查集群日志中是否有序列化异常
19.5 405 Method Not Allowed
PUT/DELETE 请求被 DefaultServlet 拒绝,在 web.xml 中修改 DefaultServlet 的 readonly 参数(但注意安全风险):
xml
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
20. 最佳实践总结
20.1 部署最佳实践
- ✅ 使用独立运行用户:永远不要以 root/Administrator 运行 Tomcat
- ✅ 分离 CATALINA_HOME 和 CATALINA_BASE:多实例部署时隔离配置和日志
- ✅ 删除默认应用 :生产环境删除
examples、docs、ROOT(除非需要) - ✅ 限制 Manager 访问:通过 RemoteAddrValve 只允许特定 IP 访问
- ✅ 不暴露 AJP 端口到公网 :AJP 应绑定
127.0.0.1,并启用requiredSecret - ✅ 使用反向代理:生产环境建议在 Nginx/Apache HTTPD 后部署 Tomcat
20.2 性能最佳实践
- ✅ 设置 -Xms = -Xmx:避免 JVM 动态扩缩堆
- ✅ 启用 NIO Connector:比 BIO 更高效(Tomcat 8.5+ 默认)
- ✅ 禁用 enableLookups:避免 DNS 反查
- ✅ 合理设置 maxThreads:根据 CPU 核心数和业务类型调整
- ✅ 启用响应压缩:对 HTML/JSON/CSS/JS 等文本类型启用 GZIP
- ✅ 使用连接池:数据库连接、HTTP 连接都应使用连接池
- ✅ 静态资源交给 Nginx:Tomcat 专注处理动态请求
20.3 安全最佳实践
- ✅ 保持版本更新:定期更新 Tomcat 和 JDK 到最新稳定版
- ✅ 启用 TLS 1.2+:禁用 SSLv3、TLS 1.0、TLS 1.1
- ✅ 隐藏版本信息:清空 Server 响应头,自定义错误页面
- ✅ 配置 LockOutRealm:防止暴力破解认证
- ✅ 设置安全 Cookie :
HttpOnly=true、Secure=true、SameSite=Strict - ✅ 添加安全响应头 :
X-Frame-Options、X-XSS-Protection、HSTS、Content-Security-Policy - ✅ 关闭目录列表 :
DefaultServlet的listings设为false
20.4 运维最佳实践
- ✅ 配置日志轮转 :设置
maxDays自动清理旧日志 - ✅ 监控关键指标:线程数、内存、GC、错误率
- ✅ 配置 JVM 崩溃转储 :
-XX:+HeapDumpOnOutOfMemoryError - ✅ 定期备份配置 :尤其是
conf/目录 - ✅ 灰度发布:集群环境下逐台更新,配合负载均衡切流
- ✅ 压测验证:性能调优后用 JMeter/ab 验证效果
附录
A. 版本官方文档链接
- Tomcat 11.0 官方文档:https://tomcat.apache.org/tomcat-11.0-doc/
- Tomcat 10.1 官方文档:https://tomcat.apache.org/tomcat-10.1-doc/
- Tomcat 9.0 官方文档:https://tomcat.apache.org/tomcat-9.0-doc/
- 版本选择指南:https://tomcat.apache.org/whichversion.html
B. 常用命令速查
bash
# 启动/停止
$CATALINA_HOME/bin/startup.sh
$CATALINA_HOME/bin/shutdown.sh
# 查看进程
ps aux | grep catalina
# 查看端口占用
lsof -i :8080
# 实时查看日志
tail -f $CATALINA_HOME/logs/catalina.out
# 查看线程状态
jstack $(pgrep -f catalina)
# 生成堆转储
jmap -dump:live,format=b,file=/tmp/heap.hprof $(pgrep -f catalina)
# 查看 JVM 内存
jstat -gcutil $(pgrep -f catalina) 5000
C. 典型 server.xml 结构速查
<Server>
<Listener .../> # 生命周期监听器
<GlobalNamingResources> # 全局 JNDI 资源
<Service>
<Executor .../> # 共享线程池(可选)
<Connector port="8080"/> # HTTP 连接器
<Connector port="8443"/> # HTTPS 连接器
<Engine>
<Realm .../> # 认证域
<Host>
<Context .../> # Web 应用(可选,通常自动发现)
<Valve .../> # 访问日志、IP 过滤等
</Host>
</Engine>
</Service>
</Server>