核心原理:
Nginx: 作为反向代理服务器和负载均衡器。它接收所有来自客户端的 HTTP/HTTPS 请求。
Tomcat 集群: 部署多个相同的 Tomcat 实例(称为节点或服务器),运行同一个Web应用。
负载分发: Nginx 根据配置的负载均衡算法(如轮询、权重、最少连接、IP哈希等)将请求转发到后端的某一个 Tomcat 实例上。
高可用: 如果某个 Tomcat 实例宕机,Nginx 能检测到并将其从可用服务器列表中剔除,将后续请求只发送给健康的实例,保证服务不中断。
部署步骤:
1. 准备环境
服务器: 至少需要两台服务器(物理机或虚拟机)。
Nginx Server (LB): 1台,用于运行 Nginx 作为负载均衡器。
Tomcat Servers (App): 至少2台,用于运行 Tomcat 应用服务器。建议使用相同的配置和操作系统。
软件:
Nginx Server: 安装 Nginx。
Tomcat Servers: 安装 JDK 和相同版本的 Tomcat。
网络: 确保所有服务器之间网络互通(Nginx 能访问所有 Tomcat 服务器的 Tomcat 端口,通常 8080)。
应用: 将你的 Web 应用(WAR 文件)部署到所有 Tomcat 实例的
webapps
目录下,确保应用状态一致。
2. 配置 Tomcat 服务器
基本配置: 在每个 Tomcat 服务器的
conf/server.xml
中,确保<Host>
配置正确指向你的应用。关闭 AJP (可选但推荐): 如果你只使用 Nginx 通过 HTTP 代理 Tomcat,可以注释掉或移除
conf/server.xml
中默认的 AJP 1.3 连接器 (<Connector port="8009" protocol="AJP/1.3" ...>
)。Nginx 通常使用 HTTP 与 Tomcat 通信。配置 HTTP 连接器: 确保 HTTP 连接器 (
<Connector port="8080" protocol="HTTP/1.1" ...>
) 是启用的,并监听合适的端口(如 8080)和地址(通常是0.0.0.0
或具体 IP)。Session 管理 (关键!): 这是集群中最重要也是最复杂的一点。默认情况下,Session 存储在单个 Tomcat 的内存中。当用户请求被分发到不同节点时,后续请求如果落到另一个节点,会导致 Session 丢失(用户需要重新登录等)。解决方案有:
a. Session 粘滞 (Sticky Session):
在 Nginx 配置中使用
ip_hash
指令(基于客户端 IP)或hash $cookie_<jsessionid_cookie_name>
(基于 Session Cookie)。优点:简单易配置,性能好(Session 不需要复制)。
缺点:不是真正的高可用(如果用户“粘”住的那个 Tomcat 宕机,该用户的 Session 丢失);负载可能不够均衡(某些 IP 请求量大)。
b. Session 复制 (Tomcat Clustering):
配置 Tomcat 集群,让节点间自动复制 Session 数据。
修改
conf/server.xml
,取消注释<Cluster>
部分,并配置Receiver
(地址/端口) 和Membership
(组播地址/端口)。在应用的
WEB-INF/web.xml
中添加<distributable/>
标签。确保应用中的所有放入 Session 的对象都实现了
java.io.Serializable
接口。优点:真正的高可用,请求可以发送到任意节点。
缺点:配置复杂;网络开销大(频繁复制 Session 数据);节点越多复制性能影响越大;存在复制延迟风险。
c. 集中式 Session 存储:
将 Session 数据存储在外部共享存储中,如 Redis、Memcached、数据库。
使用 Tomcat 的 Session Manager 实现(如
RedisSessionManager
)。优点:彻底解耦 Session 和 Tomcat 节点;高可用性好;扩展性强。
缺点:引入外部依赖(Redis/Memcached/DB)的运维复杂性和潜在单点;网络访问比本地内存慢。
选择建议: 对于中小型应用或对 Session 丢失容忍度稍高的场景,
ip_hash
是简单有效的选择。对高可用要求严格或大型应用,推荐使用 Redis 集中存储 Session。
3. 配置 Nginx 负载均衡
编辑 Nginx 配置文件: 通常是
/etc/nginx/nginx.conf
或/etc/nginx/conf.d/default.conf
或创建一个新的文件如/etc/nginx/conf.d/load-balancer.conf
。配置 upstream 块: 定义一个后端 Tomcat 服务器池。
http { upstream tomcat_cluster { # 负载均衡算法 (可选: 默认是轮询 round-robin) # least_conn; # 最少连接数 # ip_hash; # 基于客户端IP的Session粘滞 # hash $cookie_<jsessionid_cookie_name> consistent; # 基于Session Cookie的粘滞 # 定义后端Tomcat服务器列表 # 格式: server <tomcat_server_ip>:<tomcat_port> [weight=数值] [max_fails=数值] [fail_timeout=时间]; server 192.168.1.101:8080 weight=2 max_fails=3 fail_timeout=30s; # Tomcat 节点1, 权重2 server 192.168.1.102:8080 weight=1 max_fails=3 fail_timeout=30s; # Tomcat 节点2, 权重1 server 192.168.1.103:8080 backup; # 备用节点,只有当主节点都不可用时才启用 } ... }
server
: 指定 Tomcat 实例的 IP 和端口。weight
: 权重,数值越大被分配到的请求越多。用于处理性能不同的服务器。max_fails
: 在fail_timeout
时间内,允许失败的次数。超过后认为该节点不可用。fail_timeout
: 节点被标记为不可用的时间长度,以及检查失败的时间窗口。backup
: 标记为备份服务器。只有当所有非 backup 服务器都不可用时,才会启用 backup 服务器。
配置 server 块: 设置 Nginx 监听端口,并将请求代理到 upstream 池。
server { listen 80; # Nginx监听的端口 (通常是80或443) server_name yourdomain.com www.yourdomain.com; # 你的域名或服务器IP location / { # 将请求代理到上面定义的upstream池 'tomcat_cluster' proxy_pass http://tomcat_cluster; # 重要的代理设置 (通常需要添加) proxy_set_header Host $host; # 传递原始请求的主机头 proxy_set_header X-Real-IP $remote_addr; # 传递客户端真实IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 传递代理链IP proxy_set_header X-Forwarded-Proto $scheme; # 传递原始协议 (http/https) # 连接超时设置 (根据需要调整) proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; # 如果使用基于Cookie的Session粘滞,确保传递Session Cookie proxy_cookie_path / /; # 或者更精确地处理JSESSIONID路径 (根据你的应用配置) # proxy_cookie_path ~*^/.* /; } # 可选: 配置静态文件由Nginx直接处理,减轻Tomcat压力 location ~* \.(jpg|jpeg|png|gif|ico|css|js|html|txt|woff|woff2|ttf|svg)$ { root /path/to/your/static/files; # 静态文件存放的本地路径 expires 30d; # 设置浏览器缓存过期时间 access_log off; # 可选:关闭静态文件访问日志 } # 可选: 错误页面重定向 error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
HTTPS (强烈推荐):
在 Nginx 上配置 SSL/TLS 证书。
修改
server
块中的listen
指令为listen 443 ssl;
。添加
ssl_certificate
和ssl_certificate_key
指令指向你的证书和私钥文件。通常建议在 Nginx 端终止 SSL,然后以 HTTP 协议与后端的 Tomcat 通信(性能更好)。确保
proxy_set_header X-Forwarded-Proto $scheme;
配置正确,这样 Tomcat 应用才能知道原始请求是 HTTPS。
4. 测试与验证
检查配置: 运行
sudo nginx -t
检查 Nginx 配置语法是否正确。重载 Nginx: 运行
sudo systemctl reload nginx
或sudo nginx -s reload
应用新配置。访问测试: 使用浏览器或
curl
访问 Nginx 的 IP 地址或域名 (http://nginx_server_ip_or_domain
)。应该能看到你的应用。负载均衡验证:
反复刷新浏览器或使用工具(如
ab
,siege
,wrk
)发送大量请求。检查各个 Tomcat 实例的访问日志 (
logs/localhost_access_log.<date>.txt
) 或应用日志,观察请求是否被均匀(或按权重)分发到不同的节点。
Session 测试:
登录应用(触发 Session 创建)。
检查 Session Cookie(通常是
JSESSIONID
)。如果使用
ip_hash
,尝试从不同客户端 IP 访问,观察 Session 是否跟随 IP 走。如果使用 Session 复制或 Redis,尝试停掉一个正在活跃服务的 Tomcat 节点(模拟故障),然后继续操作应用,检查 Session 是否还在(没有要求重新登录或丢失数据)。
故障转移测试:
手动停止一个 Tomcat 实例 (
./bin/shutdown.sh
)。继续访问应用。Nginx 应该很快(在
fail_timeout
内)检测到该节点失败,并将后续请求只发送给健康的节点。观察 Nginx 错误日志 (
/var/log/nginx/error.log
) 是否有连接后端失败的信息。重新启动停掉的 Tomcat 实例。Nginx 应该能自动将其重新加入可用服务器池(根据健康检查机制)。
5. 监控与维护
监控:
Nginx: 监控状态码 (5xx 错误)、连接数、请求速率、上游服务器状态 (
nginx_status
模块或 Prometheus + Grafana)。Tomcat: 监控 JVM 内存、GC 情况、线程池状态、请求处理时间 (JMX, Tomcat Manager, Prometheus + jmx_exporter)。
系统: CPU、内存、磁盘 I/O、网络流量。
Session 存储 (如用 Redis): 监控 Redis 状态、内存使用、连接数。
日志分析: 定期分析 Nginx 访问日志、Tomcat 访问日志和应用日志,发现问题。
滚动更新:
更新应用时,逐个将 Tomcat 节点从 Nginx upstream 中摘除 (
down
标记或修改配置临时移除),更新应用,启动并验证,然后再将其加入集群,再处理下一个节点。使用更高级的蓝绿部署或金丝雀发布策略。
关键优势:
高可用性: 单点故障不影响整体服务。
可扩展性: 通过增加 Tomcat 节点轻松应对流量增长。
性能提升: 分散请求到多个服务器,提高并发处理能力。
灵活性: Nginx 可处理静态资源、SSL 卸载、缓存等,减轻 Tomcat 负担。
常见问题与注意事项:
Session 一致性: 这是集群的核心挑战,务必根据应用需求选择合适的方案并充分测试。
文件上传/共享存储: 如果应用涉及用户上传文件,需要确保所有 Tomcat 节点都能访问到这些文件(使用共享存储如 NFS、GlusterFS,或云存储,或在应用层处理文件同步)。
配置一致性: 确保所有 Tomcat 节点上的应用配置、环境变量、依赖库版本等完全一致。
网络延迟: 确保 Nginx 与 Tomcat 节点之间,以及 Tomcat 节点之间(如果使用 Session 复制)的网络延迟足够低。
健康检查: Nginx 的被动健康检查 (
max_fails/fail_timeout
) 是基础。对于更精确的控制,可以考虑使用主动健康检查模块(如nginx_upstream_check_module
或商业版 Nginx Plus)。防火墙: 确保 Nginx 服务器的 80/443 端口开放,并且 Nginx 能访问所有 Tomcat 节点的指定端口(如 8080),Tomcat 节点之间如果通信(Session 复制)也需要开放相应端口。