Apache 和 Tomcat 集成方案 mod_proxy 与 AJP 协议区别对比

文章导读
如果你已经在用 Apache 2.4+ 且只需要基础的负载均衡和反向代理,mod_proxy_ajp 是更轻量的选择;但如果需要实时监控、热重载 worker 或关键业务高可用,mod_jk 仍是更稳妥的方案。
📋 目录
  1. 核心差异与选型
  2. 安全加固与版本要求
  3. 分步配置实操
  4. 怎么验证是否生效
  5. 常见坑
  6. 参考来源
A A

如果你已经在用 Apache 2.4+ 且只需要基础的负载均衡和反向代理,mod_proxy_ajp 是更轻量的选择;但如果需要实时监控、热重载 worker 或关键业务高可用,mod_jk 仍是更稳妥的方案。

先说结论:mod_proxy_ajp 配置简单、维护成本低,适合中小规模集群;mod_jk 功能完整、有监控页面,适合对稳定性要求高的生产环境。

  • 适合:mod_proxy_ajp 适合已启用 mod_proxy 系列模块、追求轻量维护的场景
  • 重点看:mod_jk 支持 jkstatus 实时监控和 worker 热重载,mod_proxy_ajp 不支持
  • 别忽略:ProxyPass 路径结尾斜杠必须严格一致,stickysession 大小写敏感,Tomcat 端需配置 jvmRoute 及 AJP secret 安全密钥

核心差异与选型

Apache 和 Tomcat 整合本质是让 Apache 处理静态内容和反向代理,Tomcat 专注执行 Java Servlet/JSP。两者通讯主要有两种主流方式:mod_jk 和 mod_proxy_ajp。

AJP(Apache JServ Protocol)是定向包协议,采用二进制形式代替文本形式,Web 服务器通过 TCP 连接 Servlet 容器,多个请求可以循环重用同一个连接。mod_proxy_ajp 是 Apache 2.4+ 原生模块,无需额外编译或下载 mod_jk.so,维护成本低。但 mod_proxy_ajp 不支持运行时热重载 worker 列表,也不提供类似 jkstatus 的实时监控页面。

mod_jk 需要单独管理 workers.properties、jkstatus 页面,版本兼容性更敏感,但强在稳定性和性能方面,有关键业务监控需求时更可靠。

安全加固与版本要求

版本建议:请使用 Apache 2.4+ 版本,Apache 2.2 已停止维护且存在已知安全风险。

安全高危预警:Tomcat AJP 协议曾存在 CVE-2020-1938 (Ghostcat) 漏洞。在生产环境配置 AJP Connector 时,必须设置 secret 属性,并建议将 AJP 端口限制在内网 IP 或 localhost,严禁暴露在公网。

分步配置实操

第一步:确认 Apache 版本和已加载模块

执行命令检查当前模块状态:

httpd -v

httpd -M | grep proxy

Apache 和 Tomcat 集成方案 mod_proxy 与 AJP 协议区别对比

如果看到 proxy_module、proxy_ajp_module、proxy_balancer_module 已加载,说明可以直接用 mod_proxy_ajp 方案。

第二步:Apache 端配置 mod_proxy_ajp

在 httpd.conf 或虚拟主机配置中加载模块(Apache 2.4+ 通常默认加载,按需取消注释):

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

配置负载均衡集群(注意动静分离,仅代理动态请求路径):

<Proxy balancer://cluster>
BalancerMember ajp://192.168.123.110:8009 route=tomcat1
BalancerMember ajp://192.168.123.120:8009 route=tomcat2
ProxySet stickysession=JSESSIONID|jsessionid nofailover=On
</Proxy>
# 仅代理动态路径,静态资源由 Apache 直接处理
ProxyPass /app balancer://cluster/app
ProxyPassReverse /app balancer://cluster/app

注意 ProxyPass 和 ProxyPassReverse 的路径结尾斜杠必须严格一致,否则后端会收到错误路径。避免使用 ProxyPass / 全量代理,以免 bypass Apache 静态资源处理能力。

第三步:Tomcat 端 AJP Connector 配置

在 server.xml 中配置 AJP Connector,必须添加 secret 属性

Apache 和 Tomcat 集成方案 mod_proxy 与 AJP 协议区别对比

<Connector port='8009' protocol='AJP/1.3'
secret='YourStrongSecretKey'
maxThreads='200'
connectionTimeout='60000'
keepAliveTimeout='60000'
redirectPort='8443' />

在<Engine>标签里加 jvmRoute,这是 sticky session 的路由依据:

<Engine name='Catalina' defaultHost='localhost' jvmRoute='tomcat1'>

第四步:如果选择 mod_jk 方案

需要下载对应 Apache 版本的 mod_jk.so,放入 modules 文件夹,配置 workers.properties 文件和 mod_jk.conf,并启用 jkstatus 监控页面。

怎么验证是否生效

检查 Apache 配置语法:

httpd -t

如果返回 Syntax OK,配置语法正确。

查看已加载模块:

httpd -M | grep -E 'proxy|jk'

Apache 和 Tomcat 集成方案 mod_proxy 与 AJP 协议区别对比

访问应用后检查 Tomcat 日志,确认请求是否通过 AJP 端口到达。如果用 mod_jk,可以访问 jkstatus 页面查看 worker 状态和连接情况。

测试 sticky session 是否生效:多次刷新页面,观察是否始终路由到同一台 Tomcat(可通过在每台 Tomcat 首页显示不同标识来验证)。

安全验证:使用 netstat 确认 AJP 端口(默认 8009)仅监听在内网 IP 或 127.0.0.1,不应暴露在公网接口。

常见坑

503 错误排查方向:看到 Service Temporarily Unavailable 第一反应不是改 httpd.conf,而是检查 Tomcat 端 AJP Connector 的 maxThreads 是否与 Apache 的 MaxRequestWorkers 匹配、connectionTimeout 是否设置(AJP 默认是 -1 永不超时,容易导致连接卡死)、jvmRoute 是否漏配。

ProxyPass 路径斜杠问题:常见错误是把 ProxyPass /app ajp://127.0.0.1:8009/app 和 ProxyPass / balancer://cluster/混用在同一虚拟主机里,结果请求被重复代理或路径错乱。集群场景下只用 balancer://协议,且结尾斜杠必须一致。

stickysession 大小写敏感:JSESSIONID 大小写敏感,Tomcat 默认生成的是 JSESSIONID,不是 jsessionid。Windows 下不区分,Linux 下可能失效。

nofailover 参数含义:nofailover=On 表示 session 绑定后不漂移,适合有状态应用;若设为 Off,故障时会尝试转发到其他节点,但 session 数据可能丢失。

mod_proxy_ajp 的监控盲区:不支持运行时热重载 worker 列表,也不提供实时监控页,这点常被忽略,直到集群出问题时才发现无法快速定位哪台 Tomcat 掉线了。

CVE-2020-1938 漏洞风险:未配置 secret 的 AJP 连接器可能被利用读取 Web 应用配置文件或上传文件。务必在 Tomcat 9.0.31+ 及相应版本中配置 secret 属性。

参考来源

  • Apache HTTP Server 官方文档:mod_proxy_ajp Module
  • Apache Tomcat 官方文档:AJP Connector Configuration
  • Apache Tomcat 安全公告:CVE-2020-1938