根本原因是nginx默认不复用后端连接,每次请求新建并主动关闭,导致自身产生大量time_wait;需协议对齐(http/1.1+清空connection头)、启用upstream keepalive连接池、同步调优tomcat连接器参数,并谨慎进行系统级辅助调优。

Nginx 与上游 Tomcat 之间出现大量 TIME_WAIT,根本原因不是“连接池配置不当”本身,而是Nginx 默认不复用到后端的 TCP 连接,每次请求都新建+主动关闭,导致其自身成为 TIME_WAIT 的发起方。尤其在高并发、短响应场景下,这个问题会迅速放大。
解决思路分三层:协议对齐 → 连接复用 → 系统兜底。下面直接说关键操作。
确保 HTTP/1.1 + Connection 头正确透传
Nginx 默认用 HTTP/1.0 转发请求(不带 Keep-Alive),而 Tomcat 默认启用 HTTP/1.1 Keep-Alive。结果就是 Tomcat 想复用连接,Nginx 却每轮都断开,Tomcat 被迫被动关闭,产生大量 TIME_WAIT(若 Tomcat 主动关);但更常见的是 Nginx 主动关,TIME_WAIT 就堆积在 Nginx 本机。必须显式开启 HTTP/1.1 并清除 Connection 头:
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 Connection "" 很关键——它清空了客户端可能带的 Connection: close,也避免 Nginx 自动加 Connection: keep-alive(HTTP/1.1 下该头已无意义,反而干扰)。
启用 upstream keepalive 连接池
仅改协议不够。Nginx 还得自己维护一个到 Tomcat 的空闲连接池,否则仍会频繁建连/断连。在 upstream 块中添加:
upstream tomcat_backend {
server 127.0.0.1:8080;
# 启用连接池:最多缓存 32 个空闲长连接
keepalive 32;
# 可选:空闲连接最长保持 30 秒(超时自动回收)
keepalive_timeout 30s;
# 可选:每个连接最多服务 1000 个请求(防老化)
keepalive_requests 1000;
}
⚠️ 注意:keepalive 是 upstream 指令,不是 http 或 location 块里的。它和 keepalive_timeout(客户端侧)完全无关,别混淆。
同步调优 Tomcat 连接器参数
如果 Tomcat 侧未配合,Nginx 的 keepalive 也会失效。重点调整 `conf/server.xml` 中的 `Connector`:<connector port="8080" protocol="HTTP/1.1" connectiontimeout="5000" keepalivetimeout="30000" maxkeepaliverequests="1000" maxconnections="10000" acceptcount="1000"></connector>
-
maxKeepAliveRequests="1000":允许单连接处理 1000 个请求(与 Nginx 的keepalive_requests对齐) -
keepAliveTimeout="30000":空闲 30 秒后关闭连接,略大于 Nginx 的keepalive_timeout,避免 Tomcat 先断 -
connectionTimeout设低些(如 5s),防止慢连接长期占位
不建议设 maxKeepAliveRequests="1"(即禁用 keepalive),这会让 Tomcat 每次都断连,反而加剧问题。
系统级辅助调优(谨慎启用)
当上述应用层优化到位后,TIME_WAIT 数量应明显下降。若仍有压力,可微调内核参数:# 编辑 /etc/sysctl.conf net.ipv4.tcp_tw_reuse = 1 # 允许 TIME_WAIT 套接字被快速重用(安全) net.ipv4.tcp_fin_timeout = 30 # FIN_WAIT_2 状态超时缩短(间接缓解) net.ipv4.tcp_max_tw_buckets = 5000 # 防止 TIME_WAIT 占满内存(设合理上限)
⚠️ 绝对不要开 tcp_tw_recycle = 1(尤其在 NAT 环境如云服务器、容器中),它依赖时间戳且极易导致连接失败。
最后执行 sysctl -p 生效,并用 ss -s | grep -i "time-wait" 或 netstat -ant | grep TIME_WAIT | wc -l 验证效果。
不复杂但容易忽略











