AJP比HTTP代理更高效,因它是二进制协议、减少解析开销、精准透传客户端信息;但需Tomcat启用AJP connector(默认8009端口),且两端配置需协同调优。

为什么用 AJP 而不是 HTTP 代理?
直接走 mod_proxy_http 看似简单,但实际在 Apache + Tomcat 场景下,mod_proxy_ajp 更省资源、更准传客户端信息(比如真实 IP、SSL 状态)。AJP 是二进制协议,避免了 HTTP 解析开销,尤其在高并发静态+动态混合请求时,Tomcat 的 AJP connector 线程利用率明显更高。
关键前提是:Tomcat 的 server.xml 必须启用 AJP connector,且默认端口是 8009。别只改 Apache 配置却忘了开 Tomcat 这边——这是最常卡住的点。
Apache 启用 mod\_proxy\_ajp 的最小必要配置
确保模块已加载:
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
然后在虚拟主机或主配置中写代理规则:
<Proxy *>
Require all granted
</Proxy>
ProxyPass /app ajp://127.0.0.1:8009/app
ProxyPassReverse /app ajp://127.0.0.1:8009/app
-
ProxyPass和ProxyPassReverse的路径必须严格一致(包括结尾斜杠),否则重定向会出错 - 若后端 Tomcat 启用了
remoteIPValve或需要真实 IP,Apache 必须加RequestHeader set X-Forwarded-For %{REMOTE_ADDR}s,仅靠 AJP 不自动透传该头 - AJP 不支持 WebSocket,要代理 ws/wss,得额外配
mod_proxy_wstunnel并走 HTTP 协议
常见 503 错误的三个真实原因
访问时返回 Service Temporarily Unavailable,不是配置写错了,而是下面这些情况之一:
- Tomcat 的 AJP connector 被禁用或绑定到了
127.0.0.1,而 Apache 尝试从另一 IP(如 IPv6 ::1)连接 —— 检查server.xml中<connector port="8009" protocol="AJP/1.3" address="127.0.0.1"></connector> - 防火墙或 SELinux 拦截了 8009 端口通信(CentOS/RHEL 上常见),临时关 SELinux 测试:
setenforce 0 - Apache 的
mod_proxy工作进程被 kill 或卡死,重启前先看日志:tail -f /var/log/httpd/error_log | grep -i ajp,留意connection refused或timeout
性能调优不能只调 ProxyPass 参数
ProxyPass 支持 retry=60、keepalive=On 等参数,但真正影响吞吐的是 Tomcat 端的 AJP connector 配置:
- Tomcat 的
maxThreads要和 Apache 的MaxRequestWorkers匹配,否则一边积压一边空转 - AJP 默认不启用 keepalive,需显式设
connectionTimeout="60000"和keepAliveTimeout="60000"(单位毫秒) - 如果 Apache 前面还有 CDN 或 LB,务必在 Tomcat 的
RemoteIpValve中把remoteIpHeader设为X-Forwarded-For,否则request.getRemoteAddr()拿到的永远是 Apache 的 IP
AJP 的高效是有前提的:两端都按真实负载调参,而不是只改 Apache 一行 ProxyPass 就以为万事大吉。

















