Tomcat全栈指南:从入门到精通

Apache Tomcat 完整知识总结与使用教程


目录

  1. [Tomcat 简介与历史](#Tomcat 简介与历史)
  2. 版本选择指南
  3. 安装与目录结构
  4. 核心架构解析
  5. 核心组件详解
  6. 请求处理流程
  7. 配置文件详解
  8. [Web 应用部署](#Web 应用部署)
  9. [SSL/TLS 配置](#SSL/TLS 配置)
  10. 性能调优
  11. [JVM 调优](#JVM 调优)
  12. 集群与会话复制
  13. 安全加固
  14. 日志管理
  15. 类加载机制
  16. 虚拟主机配置
  17. [与 Nginx/Apache HTTPD 集成](#与 Nginx/Apache HTTPD 集成)
  18. 监控与管理
  19. 常见问题排查
  20. 最佳实践总结

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)

  1. 从官网下载 .zip.exe 安装包
  2. 解压到目标目录(如 C:\tomcat
  3. 运行 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 &quot;%r&quot; %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 &quot;%r&quot; %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&amp;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 &quot;%r&quot; %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.xmllogback.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 相反):

  1. Bootstrap + Extension ClassLoader(JVM 核心类)
  2. WEB-INF/classes(应用自身类)
  3. WEB-INF/lib/*.jar(应用依赖)
  4. 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 性能问题

问题:响应变慢

  1. 查看线程状态:jstack <pid> 或通过 JMX 查看
  2. 检查是否有大量线程处于 BLOCKED 状态(数据库连接池耗尽)
  3. 检查 GC 日志,是否频繁发生 Full GC
  4. 确认 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 -Lfirewall-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:多实例部署时隔离配置和日志
  • 删除默认应用 :生产环境删除 examplesdocsROOT(除非需要)
  • 限制 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:防止暴力破解认证
  • 设置安全 CookieHttpOnly=trueSecure=trueSameSite=Strict
  • 添加安全响应头X-Frame-OptionsX-XSS-ProtectionHSTSContent-Security-Policy
  • 关闭目录列表DefaultServletlistings 设为 false

20.4 运维最佳实践

  • 配置日志轮转 :设置 maxDays 自动清理旧日志
  • 监控关键指标:线程数、内存、GC、错误率
  • 配置 JVM 崩溃转储-XX:+HeapDumpOnOutOfMemoryError
  • 定期备份配置 :尤其是 conf/ 目录
  • 灰度发布:集群环境下逐台更新,配合负载均衡切流
  • 压测验证:性能调优后用 JMeter/ab 验证效果

附录

A. 版本官方文档链接

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>

相关推荐
hrhcode2 小时前
【java工程师快速上手go】三.Go Web开发(Gin框架)
java·spring boot·golang
敖正炀2 小时前
CountDownLatch 详解
java
海兰2 小时前
【Spring AI】从一个MCP小实例开始
java·人工智能·spring
Rick19932 小时前
Spring Boot自动装配原理
java·spring boot·后端
我命由我123452 小时前
Android Jetpack Compose - 组件分类:布局组件、交互组件、文本组件
android·java·java-ee·kotlin·android studio·android jetpack·android-studio
Devin~Y2 小时前
大厂内容社区面试实录:从 Spring Boot 微服务到 AI RAG 问答(附详细解析)
java·spring boot·redis·elasticsearch·spring cloud·微服务·kafka
Lenyiin2 小时前
Python数据类型与运算符:深入理解Python世界的基石
java·开发语言·python
fīɡЙtīиɡ ℡2 小时前
【SpringAi最新版入门(二)】
java·javascript·css·人工智能·css3
小江的记录本2 小时前
【大语言模型】大语言模型——核心概念(预训练、SFT监督微调、RLHF/RLAIF对齐、Token、Embedding、上下文窗口)
java·人工智能·后端·python·算法·语言模型·自然语言处理