news 2026/10/16 14:47:47

Nginx+Tomcat动静分离与负载均衡:Java Web集群部署实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Nginx+Tomcat动静分离与负载均衡:Java Web集群部署实战

先说结论:这套 Nginx + Tomcat 的动静分离 + 负载均衡方案,是 Java Web 项目从单机走向集群的第一道坎,也是我近几年帮团队做架构升级时最常用到的基础组合。Nginx 处理静态文件的高并发能力和 Tomcat 处理动态业务的稳定性各有分工,两者配合下来,既能扛住流量,又能降低后端压力。只要你手里有一个 Java Web 项目,不管规模大小,这篇文章的思路和配置都能直接用。我会从为什么需要这套架构讲起,再到实际部署、Nginx 配置、会话保持、压测验证,最后把日常最容易踩的坑都整理出来。

一套架构的选型,从来不是越新越好,而是越适合自己团队越好。Nginx + Tomcat 的组合,到今天依然是中小型 Java Web 项目最稳的起点之一,值得你花半小时把整条链路跑通。

1. 动静分离与负载均衡的设计思路

1.1 动静分离到底在解决什么问题

很多刚接触这套架构的人会有一个疑问:Tomcat 本身也能处理静态资源,为什么非要把图片、CSS、JS 抽出来交给 Nginx?

最直接的原因是性能差异。Tomcat 内部是一个 Servlet 容器,请求进来后要经过 Connector、Engine、Host、Context、Servlet 这条链路,每多一层处理就会消耗 CPU 和内存。哪怕只是一个读取文件的简单请求,Tomcat 也会走一遍完整的容器过滤链。而 Nginx 是用事件驱动模型实现的,核心就是一个高性能的静态文件服务器,读取本地文件、直接响应请求,整个过程基本不依赖后端业务逻辑。

我打个比方:Tomcat 就像一位专业知识扎实的工程师,你让他画图纸、写代码、解决复杂问题,他做得很好,但如果你让他同时去处理一万个文件复印的活儿,他也应付得来,只是成本高得吓人。Nginx 则像一个专门做收发件的窗口,只负责把文件、静态资源快速传递出去,不掺和业务,自然速度快、并发高。

一台普通配置的 Tomcat,默认配置下能够稳定支撑的并发连接数大概在几百这个量级,而 Nginx 单机扛几万并发连接是很常见的事。动静分离就是把静态资源这种高频率、低计算量的请求,从 Tomcat 手里接过来,让 Tomcat 专心处理 JSP、Spring MVC、接口这类真正需要计算的任务。这样两边的资源利用率都能上来,整个系统的吞吐量也跟着上涨。

1.2 负载均衡解决的是单点瓶颈

如果说动静分离是替 Tomcat 减负,那负载均衡就是替 Tomcat 增加人手。

单台 Tomcat 的能力是有上限的,哪怕你把它堆到性能最优,也总有扛不住的时候。尤其是在用户量上涨之后,数据库压力先不谈,单是应用服务器这一层,线程池满、连接超时、CPU 飙涨这些问题就会轮流出现。这个时候你不是去压榨单台机器,而是应该横向扩展,部署两台、三台甚至更多 Tomcat 节点,让 Nginx 作为统一的入口,把请求分发到后端的各个节点上。

分发的过程就是负载均衡。Nginx 会根据配置的算法,把请求合理地送到不同的 Tomcat 上。一台挂了,其他节点继续工作,这就是故障转移;流量大了,多加两台 Tomcat,水平扩容,这就是弹性扩展。

我当年负责的一个模拟项目,日活冲到一定程度后单台 Tomcat 频繁出现 Connection refused,高峰时段用户明显感觉页面打开变慢。后来接入 Nginx 做负载均衡,后端从一台扩到三台 Tomcat,QPS 翻了一倍多,慢请求比例大幅下降,关键是整个过程不需要改动任何项目代码,只是把部署拓扑改了一下。这种“不改代码、只改架构”的提升,对业务来说是最安全的优化方式。

1.3 适合这套架构的典型场景

Nginx + Tomcat 动静分离与负载均衡的组合,最适合这几类情况:

第一类是传统的 Java Web 项目,用 JSP、Servlet 开发,静态资源放在 Web 应用目录下。这种项目一般已经有了 Tomcat 部署基础,引入 Nginx 是在前端加一层,改动成本最低。

第二类是团队服务器资源有限的小型项目。没有专门的 CDN,也没有微服务网关,把所有静态资源直接交给 Nginx 托管,相当于用最低的成本获得了接近 CDN 的静态资源加速效果。

第三类是正在从单机向集群演进的项目。比如你原本只有一台服务器,客户越来越多,准备再加机器,这时候用 Nginx 做统一入口和负载均衡,是最平滑的过渡方式。

当然,如果你的项目已经上了 Spring Cloud 这类微服务框架,通常会搭配 Gateway 或专门的流量网关,Nginx 更多是作为最外层入口存在。但在内层服务之间做负载均衡的思路,和这里讲的 Nginx upstream 机制,本质上是一脉相承的。

2. 环境准备与基础部署

2.1 组件版本怎么选

部署这套环境,需要三样东西:JDK、Tomcat、Nginx。版本搭配其实没有太多玄学,关键是稳定两个字。

我自己的习惯是优先选择 Linux 平台,用 CentOS 7 或者 Ubuntu 20.04 这类长期支持版本。JDK 我一般用 8 或 11,Tomcat 8.5 或 9.0,Nginx 用 1.20 左右的稳定版就可以。这套组合经过大量生产环境验证,踩过坑的人比较少,社区资料也多,遇到问题容易查。

下表是我常用的版本组合,你可以直接照着来:

组件推荐版本下载说明
JDK8u202 或 11.0.x注意别用最新大版本,部分 Tomcat 旧版本不兼容
Tomcat8.5.x 或 9.0.x两个版本 API 差异不大,部署方式一样
Nginx1.20.x稳定版,自带常用模块,无需编译扩展
操作系统CentOS 7 / Ubuntu 20.0464 位系统,内存至少 2G

这里有一个细节:Tomcat 和 JDK 版本的兼容性,不是所有版本都能随便配。比如 Tomcat 10 采用的是 Jakarta EE 规范,包名从 javax.* 换成了 jakarta.*,这意味着部署在 Tomcat 9 上好好的 WAR 包,放到 Tomcat 10 很可能会启动报错。如果你项目还在用老代码,保守一点选 Tomcat 9 更省心。

2.2 安装部署三步走

创建目录结构。我习惯把软件都放在 /usr/local 下面,项目数据放在 /data,这样软件和业务数据分开,后续备份也清晰。我常做的目录结构大概是这样的:

mkdir -p /usr/local/nginx mkdir -p /usr/local/tomcat-node1 mkdir -p /usr/local/tomcat-node2 mkdir -p /data/static

下载并解压。这里以 Tomcat 为例:

wget https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.54/bin/apache-tomcat-9.0.54.tar.gz tar -zxvf apache-tomcat-9.0.54.tar.gz -C /usr/local/tomcat-node1 --strip-components=1

Nginx 的安装也类似,如果使用 yum 或 apt 安装,记得确认版本不是太旧。我个人偏好的方式是直接官网下载源码包,然后编译安装,虽然多几步命令,但这样以后想加第三方模块,比如 HTTP 健康检查模块,重编一次就能带上,灵活性更高。

启动服务验证。先启动 Tomcat,默认监听 8080 端口,看到 Tomcat 的欢迎页就说明 Java 环境没问题:

/usr/local/tomcat-node1/bin/startup.sh curl -I http://127.0.0.1:8080

再启动 Nginx,默认监听 80 端口:

/usr/local/nginx/sbin/nginx curl -I http://127.0.0.1

这一步验证的是最基础的链路:Nginx 能访问、Tomcat 能访问。后面的动静分离和负载均衡都要在这两个基础上叠加配置。

2.3 部署测试项目与静态资源

为了后面真正验证动静分离的效果,不能光看欢迎页,得准备一个有点业务量的测试项目。

先准备一个最简单的 Java Web 项目。假如你有一个叫 demo 的 WAR 包,直接丢到 Tomcat 的 webapps 目录下,然后把 Tomcat 的默认 ROOT 目录清空,避免干扰测试。这里用的是一个很简单的做法:

rm -rf /usr/local/tomcat-node1/webapps/ROOT cp demo.war /usr/local/tomcat-node1/webapps/ROOT.war

我这里把 WAR 包部署成 ROOT 的原因,是希望访问 / 就直接进入项目,不需要在 URL 里再带项目名。生产环境不建议这么搞,但测试环境这样最省事。

然后准备静态资源。动静分离的前提是 Nginx 有一个静态资源目录,我们准备把项目的图片、CSS、JS 都搬到这里。先在 /data/static 下面建好目录结构:

mkdir -p /data/static/static/css mkdir -p /data/static/static/js mkdir -p /data/static/static/img echo "body{background:#f0f0f0;}" > /data/static/static/css/demo.css echo "console.log('static js')" > /data/static/static/js/common.js

注意,我把静态资源放在 /data/static 下面,但请求路径上还会有一层 static 前缀,这是刻意为之。如果你直接请求 http://127.0.0.1/static/css/demo.css,Nginx 会在 root 指定的 /data/static 下面找 static/css/demo.css,也就是实际路径 /data/static/static/css/demo.css。这种对应关系要理清楚,不然配置很容易出错。

3. Nginx 核心配置:动静分离落地

3.1 配置负载均衡 upstream 池

Nginx 的负载均衡核心是 upstream 模块。它定义了一组后端服务器,Nginx 会把请求按照某种策略分发给这组服务器。

在最简单的情况下,配置长这样:

upstream tomcat_pool { server 127.0.0.1:8081 weight=1; server 127.0.0.1:8082 weight=1; }

upstream 这个名字可以自定义,我习惯用 tomcat_pool,这样一眼就能看出它的用途。server 指令后面跟的是后端 Tomcat 的地址和端口。

这里有个权重参数 weight,默认值是 1,表示两台机器分配到的请求数量相当。如果你的服务器性能不同,可以给高性能的机器加大权重,比如 weight=2,它能分到两倍的请求量。这个参数在扩容的时候很实用,比如新机器配置高,你先给它权重大一些,让流量逐步倾斜过去,观察几天没问题再调整。

3.2 location 规则实现动静分离

动静分离的核心,是通过 location 匹配规则,把不同后缀的请求引导到不同的处理位置。

静态资源请求交给 Nginx 本地文件系统,动态请求反向代理给 Tomcat。最典型的配置如下:

server { listen 80; server_name localhost; # 静态资源请求交给 Nginx 直接处理 location ~* \.(css|js|png|jpg|jpeg|gif|bmp|ico|svg)$ { root /data/static; expires 7d; access_log off; } # 动态请求统一转发给 Tomcat 集群 location / { proxy_pass http://tomcat_pool; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }

这段配置我建议你实际敲一遍,因为里面有几个极易出错的细节。

第一,正则匹配 location 用了 ~* 前缀,表示不区分大小写。如果你想要精确控制,可以用 ~ 表示区分大小写。但实际生产环境中,文件后缀大小写的问题经常出现,所以用 ~* 更稳妥。

第二,root 后面跟的路径,要和实际静态资源的存放路径完全一致,否则会 404。

第三,expires 7d 是让浏览器对这些静态资源缓存 7 天,这个参数对减少请求量的帮助非常大,尤其在图片多、JS/CSS 文件多的项目里,一次全量缓存能省下大量重复请求。

这里有一个非常重要的匹配顺序问题。Nginx 的 location 匹配,不是按从上到下依次匹配的,而是先做前缀匹配,再做正则匹配,正则匹配到的优先级更高。换句话说,即使下面那条 location / 也能匹配上 /static/css/demo.css,但由于上面那条正则 location 更精确,最终请求还是会交给静态资源处理。这正是动静分离能够生效的本质原因。

3.3 proxy_pass 结尾斜杠的坑

proxy_pass 的 URI 处理逻辑,是很多新手踩坑的重灾区,值得单独拿出来讲一讲。

先看两种写法:

proxy_pass http://tomcat_pool;

和

proxy_pass http://tomcat_pool/;

区别在于结尾多了一个斜杠。当 proxy_pass 后不带 URI(也就是没有路径部分)时,Nginx 会把原始请求的 URI 原封不动地传给后端。当 proxy_pass 后带 URI 时,Nginx 会把 location 匹配的部分替换成 proxy_pass 中指定的路径,再传给后端。

举个例子,如果请求是 http://127.0.0.1/api/user/info:

  • 使用 proxy_pass http://tomcat_pool; 时,后端 Tomcat 收到的是 /api/user/info。
  • 使用 proxy_pass http://tomcat_pool/; 时,后端 Tomcat 收到的是 /user/info,因为 /api 部分被替换掉了。

你写配置时,必须是完全清楚这两种写法的语义差异,才能避免走弯路。我在给生产环境排错时,遇到过后端接口正常、前端却 404 的情况,最后定位到就是 proxy_pass 结尾多了一个斜杠导致的。若是你有不确定的,我会这样检查:凡是没有特殊替换需求的,我会统一写成不带 URI 的 proxy_pass,让请求 URI 原样透传,这样理解和排查都简单。

3.4 关键代理参数逐一说明

动态请求交给 Tomcat 时,并不是简单转发就完事,还涉及几个 HTTP 头参数,这些参数会在后端接收请求时发挥作用。

proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

第一行设置 Host 头。如果不设置,后端 Tomcat 收到的请求 Host 会是 Nginx 自身的地址(比如 127.0.0.1),这会给基于 Host 做虚拟主机或域名判断的后端应用带来困扰。设置成 $host 后,后端拿到的就是真实的访问域名。

第二行设置 X-Real-IP。Nginx 和后端 Tomcat 之间的连接,源 IP 永远是 Nginx 所在机器的 IP,这样后端就无法获取真正的客户端 IP。通过 X-Real-IP 这个头,把客户端的真实 IP 传给后端。

第三行是 X-Forwarded-For,它会在原有值的基础上追加客户端的 IP。如果中间还有多层代理,这个头会累积起来,形成一个 IP 列表,最左边的就是最原始的客户端 IP。

除了请求头,超时参数也很关键。我会在 proxy 配置里加上这几行:

proxy_connect_timeout 5s; proxy_read_timeout 10s; proxy_send_timeout 10s;

connect_timeout 是 Nginx 和后端 Tomcat 建立 TCP 连接的超时时间。如果 Tomcat 已经挂了但端口还能被探测到,这个参数决定了 Nginx 多久会放弃。read_timeout 和 send_timeout 则是两次读写操作之间的间隔超时,单位是秒。如果你的后端有耗时较长的接口,比如文件导出,这几个值需要调大,否则 Nginx 会在中间主动断开连接,前端就会看到 504。

如果你的系统有文件上传功能,还要加上 client_max_body_size 限制。默认情况下 Nginx 限制了请求体大小为 1MB,超过这个大小直接返回 413。很多人部署完上传功能,小文件正常,大文件就失败,不用怀疑,十有八九是这里的问题。按需改大,例如:

client_max_body_size 20m;

4. 负载均衡算法与会话保持

4.1 默认轮询与权重轮询

Nginx 负载均衡默认使用轮询算法,也就是请求按时间顺序逐一分配到不同的后端服务器。两台 Tomcat 的话,第一个请求去 A,第二个去 B,第三个又回到 A,循环往复。这种算法实现简单,后端服务器配置均衡时效果还不错。

加权轮询则是在轮询的基础上,加入了 weight 参数。Nginx 会根据权重比例来分配请求,例如:

upstream tomcat_pool { server 127.0.0.1:8081 weight=2; server 127.0.0.1:8082 weight=1; }

这样分配的结果是,8081 端口上的 Tomcat 接收大约三分之二的请求,8082 接收大约三分之一。这种模式适合后端服务器配置不对等的场景,比如一台是 4 核 8G,一台是 2 核 4G,前者完全可以承担更多流量。

4.2 ip_hash 实现会话保持

光有轮询还不够。如果你的项目使用了 Session 保存用户登录状态,而且还没有做 Session 共享,默认的轮询策略会带来一个很严重的问题:用户第一次请求被分到 A 节点,登录状态存在了 A 节点上;第二次请求被分到 B 节点,B 节点发现没有这个用户的 Session,于是把你踢回登录页。

解决这个问题最简单的办法,是使用 ip_hash 负载均衡策略。它的原理很简单:Nginx 会根据客户端 IP 计算出一个哈希值,同一个 IP 的请求,始终会被定向到同一台后端服务器。这样用户只要第一次登录时落在某台机器上,后续的请求也都会落在这台机器上,Session 的问题就避免了。

upstream tomcat_pool { ip_hash; server 127.0.0.1:8081; server 127.0.0.1:8082; }

需要注意的是,ip_hash 适合在一个办公室、同一个出口 IP 访问的场景下使用。但在移动网络环境下,用户的出口 IP 可能会频繁变化,这种情况下 ip_hash 的效果就会打折扣。

4.3 后端节点健康检查与故障转移

Nginx 的 upstream 里有两个参数和故障转移密切相关:max_fails 和 fail_timeout。

默认情况下,max_fails 为 1,fail_timeout 为 10 秒。意思是,Nginx 在 10 秒内,只要发现后端服务器有 1 次请求失败,就会在接下来的 10 秒内,把这台服务器标记为不可用,请求不再分配给它。过了这个时间窗口,Nginx 再尝试一次,如果能连通,就重新恢复调度。

我一般会按业务情况调整这些参数,例如:

upstream tomcat_pool { server 127.0.0.1:8081 max_fails=3 fail_timeout=30s; server 127.0.0.1:8082 max_fails=3 fail_timeout=30s; }

将 max_fails 提高为 3,是为了避免一次性故障就触发下线,毕竟有些错误是临时性的。fail_timeout 增加到 30 秒,也是为了让节点下线后有足够的时间恢复。

这里有一个容易误解的点:Nginx 的主动健康检查机制(定期向后端发探测请求)是商业版才带的功能,开源版默认只有被动的健康检查,也就是靠真实请求来判断后端是否可用。如果你需要主动探活,可以使用第三方健康检查模块,或者在 Nginx 前面再加一层探测脚本。

4.4 生产环境 Session 共享的更优解

ip_hash 是治标不治本的方案。虽然能解决会话保持问题,但它也带来一个缺点:一旦某台 Tomcat 宕机,这台机器上所有的用户 Session 都会丢失,用户被迫重新登录。而且这种粘性会话会让负载分配不均匀,某些大流量 IP 可能会长期集中在一台机器上。

生产环境我更推荐集中式 Session 管理。常见方案是把 Session 统一存放到 Redis 等缓存中间件中,所有 Tomcat 节点都从同一个地方读写 Session。这样不管请求落到哪个节点,都能拿到一致的会话数据,彻底摆脱对 ip_hash 的依赖。

实现方式通常有两种。一种是使用 Spring Session,在项目里引入依赖后,Tomcat 的 Session 会被透明地替换成 Redis 存储,对业务代码完全无感。另一种是在 Tomcat 层面配置 Session Manager,使用官方提供的 Redis Session Manager 扩展。

我的建议是,如果项目很小、短期不想动代码,先用 ip_hash 过度是可以接受的。但如果项目已经开始集群化部署,为了未来的扩展和维护,尽早接入集中式 Session 才是正路。Session 共享这件事,越早做越轻松,等项目规模大了再改,涉及的面就会广很多。

5. 验证与压测:效果到底如何

5.1 用 curl 验证动静分离是否生效

配置改完了,先不要急着压测,用 curl 随手验证一下每个请求被谁处理了。Nginx 响应静态文件和 Tomcat 响应请求,响应头里有明显区别。

先看动态请求的响应:

curl -I http://127.0.0.1/demo/index.jsp

观察响应头中的 Server 字段。如果这条请求经过 Nginx 转发给 Tomcat,Server 字段会显示 Apache-Coyote/1.1,这是 Tomcat 的标识。如果是 Nginx 直接返回的,Server 字段会显示 nginx。

再验证静态资源:

curl -I http://127.0.0.1/static/css/demo.css

如果响应头里的 Server 是 nginx,并且带有 Expires 和 Cache-Control 头,说明静态资源确实被 Nginx 接管了,动静分离在生效。

我还习惯检查一下访问日志,Nginx 的 access.log 里,静态资源请求和动态接口请求的来源地址都指向客户端 IP,而后端 Tomcat 的访问日志里,来源地址是 Nginx 的 IP。这一点也可以用来辅助确认链路是否正常。

5.2 用 ab 压测对比单机与集群

配置验证通过后,可以做一次简单的压测对比,看看负载均衡带来了多少提升。这里我使用 Apache ab 工具,如果你没有装 Apache,也可以用 wrk 或 vegeta。

先压单台 Tomcat 作为基线:

ab -n 2000 -c 100 http://127.0.0.1:8081/demo/index.jsp

我这里的模拟结果是 QPS 大概在 9000 左右,平均响应时间 10ms。当然这个数据跟你机器配置和页面复杂度密切相关,重点是看对比趋势。

然后通过 Nginx 访问两台 Tomcat:

ab -n 2000 -c 100 http://127.0.0.1/demo/index.jsp

在同样的并发情况下,QPS 通常会提升到单台的 1.8 倍到 2 倍。这里有一个比较重要的指标是失败率(Failed requests),如果出现大量失败,说明后端某一台节点可能存在性能瓶颈,或者配置不当。

5.3 观察后端日志确认真实命中

还有一种更直接的验证方式,是同时打开两台 Tomcat 的访问日志,观察请求是否真的被分发到了两台机器。

tail -f /usr/local/tomcat-node1/logs/localhost_access_log.txt tail -f /usr/local/tomcat-node2/logs/localhost_access_log.txt

同时发起一批请求,你会发现两台机器的日志都在滚动。这里有个细节,如果你使用了 ip_hash,同一个 IP 的请求只会出现在一台机器的日志里;如果你用的是默认轮询,请求会交替出现在两台机器上。

这个验证步骤虽然简单,但在排查“负载均衡不生效”这类问题时特别关键,因为它能直接定位问题到底出在 Nginx 配置,还是出在后端节点。

6. 常见问题与排查技巧实录

6.1 静态资源 404 或样式丢失

这是动静分离里最常见的问题。页面能打开,但 CSS、JS、图片全部 404,页面完全变形。

排查路径基本上就两条。第一条是看 Nginx 的错误日志,通常会给出具体的文件路径。如果日志显示 no such file or directory,说明路径拼接出了问题。需要检查 root 指定的目录和 URL 路径之间的映射关系是否一致。

给你一个快速验证的方法:根据请求 URL 和 root 配置,手动拼接出 Nginx 期望的物理路径,然后在服务器上用 ls 确认这个文件是否存在。比如请求是 /static/css/demo.css,root 是 /data/static,那 Nginx 找的文件就是 /data/static/static/css/demo.css。

第二条排查路径是看浏览器开发者工具里的实际请求 URL。如果你项目里的 CSS 引用路径是绝对路径 /static/css/demo.css,那就没有问题。如果引用的是 project/static/css/demo.css 这种相对路径,通过负载均衡入口访问时,很可能会因为 Nginx 转发路径的细微差异导致路径错乱。

6.2 Session 丢失,用户频繁掉登录状态

用户登录后,操作着操作着就被踢回登录页,这是负载均衡引入后最典型的问题。

如果你没有配置 ip_hash,也没有 Session 共享,那出现这个问题几乎是一定的。排查方式很简单:用两个不同浏览器登录系统,或者同一浏览器开普通窗口和隐身窗口,观察登录后在两台 Tomcat 的日志里有没有都出现请求。

如果确认是 Session 问题,通常有两种解法:小项目临时用 ip_hash 顶上,生产环境上 Redis 共享 Session。我之前接手的某跨平台系统项目就遇到过这个坑,当时技术负责人图省事用了轮询,结果上线第二天就收到大量掉线反馈,临时改 ip_hash 先应急,同时安排研发花了两天时间接入了集中式 Session,才彻底解决。

6.3 后端应用获取不到客户端真实 IP

做完负载均衡之后,后端 Tomcat 记录的客户端 IP 全部变成了 Nginx 的 IP,导致日志分析、用户定位功能全部失效。

这个问题前面已经提过,需要在 Nginx 配置里加上 X-Real-IP 和 X-Forwarded-For 请求头,同时在后端 Tomcat 的 server.xml 里,给 Engine 或 Host 配置 RemoteIpValve,这样 Tomcat 才会信任 Nginx 传过来的 IP 头,并把它作为实际的客户端地址。

<Valve className="org.apache.catalina.valves.RemoteIpValve" remoteIpHeader="X-Forwarded-For" protocolHeader="X-Forwarded-Proto" />

这里有一个安全细节:如果你是直接暴露在公网的 Nginx,任何客户端都可以伪造 X-Forwarded-For 头。所以在让 Tomcat 信任这个头之前,要确保只有 Nginx 的流量能到达 Tomcat,而不是让 Tomcat 端口也直接暴露在公网。否则,伪造这个头可以让后端记录到错误的 IP。

6.4 50X 错误速查

最后整理一个 50X 错误的排查速查表,直接对照处理。

错误码常见原因处理动作
502 Bad Gateway后端 Tomcat 未启动、端口错误、防火墙拦截检查后端服务状态、端口连通性
503 Service Unavailable后端节点全部失败被下线检查后端节点恢复情况,调大 fail_timeout
504 Gateway Timeout后端接口响应超时调大 proxy_read_timeout,排查后端慢查询
413 Request Entity Too Large上传文件超过 Nginx 限制调大 client_max_body_size

502 是出现频率最高的,排查时先用 telnet 或 nc 探测后端端口是否通,再确认 Tomcat 进程是否存活。如果后端服务是好的,Nginx 还是 502,那就要检查 upstream 里是否配置了错误的地址,或者后端节点是否被之前的失败请求触发了临时下线。

504 则要区分情况。如果只是某一个长时间的接口偶尔超时,调大 proxy_read_timeout 就能解决。如果后端接口普遍响应缓慢,那要排查的是 Tomcat 线程池、数据库慢查询和应用本身的性能问题,调大超时只是掩耳盗铃。

搭这套架构从开始到落地,我通常半天内就能完成,真正耗时的是后续的慢慢调优和排错。最后再分享一个小技巧:每次改完 Nginx 配置,先跑一遍 nginx -t 检查语法,再执行 nginx -s reload,不要直接用 restart。Reload 会平滑切换配置,让正在处理的请求不中断,这在生产环境里是必须养成的好习惯。这套架构不复杂,但每一个细节都值得认真对待。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 14:47:40

雷达与红外图像跟踪融合源代码:从航迹关联到信息滤波的工程实现

简介&#xff1a;面向雷达与红外多传感器目标跟踪研究者的源代码资料&#xff0c;围绕卡尔曼滤波在异类传感器数据融合中的应用展开&#xff0c;适合学习目标检测、状态估计与融合算法的开发者参考。压缩包共10个文件、约14KB&#xff0c;以9个MATLAB脚本和1个TXT说明为主&…

作者头像 李华
网站建设 2026/10/16 14:46:30

Linux安全加固手册:从账号到文件系统的四层防线

简介&#xff1a;LINUX安全加固手册面向Linux运维工程师、系统管理员与安全入门者&#xff0c;是一份按模块组织的加固指南&#xff0c;覆盖系统安装阶段的安全选项、root密码设置、网络接口配置&#xff0c;以及用户帐号与密码管理策略。手册以PDF形式提供&#xff0c;单个文件…

作者头像 李华
网站建设 2026/10/16 14:44:28

2026年IDE使用简记:AI、远程开发与工作流优化

从2023年到现在&#xff0c;我保持着一个谈不上多正式的习惯&#xff1a;每隔半年&#xff0c;把当前在用的IDE、编辑器、配置文件和一些踩坑记录整理成一份“简记”。最开始是怕自己忘&#xff0c;后来发现这套笔记比很多教程都管用&#xff0c;因为它完全是按我的真实工作流写…

作者头像 李华
网站建设 2026/10/16 14:43:25

OpenCV工业计数系统:零GPU实时拍照、轮廓分析与Excel自动存表

简介&#xff1a;本资源是一份基于OpenCV的本科课程设计完整报告&#xff0c;面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生&#xff0c;解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓提取与边缘检测&#xff08;Canny/Hough&a…

作者头像 李华