一、前言:为什么用 OpenResty 代理 Tomcat?
你可能已经用 Nginx 代理过 Tomcat,但遇到过这些问题吗?
- ❌ 静态配置 upstream,无法动态扩缩容
- ❌ 后端 Tomcat 挂了,请求仍被转发(无健康检查)
- ❌ 无法根据 Header 或参数路由到不同 Tomcat 集群
- ❌ 缺少细粒度限流、鉴权等网关能力
OpenResty = Nginx + LuaJIT ,让你在代理 Tomcat 的同时,注入智能逻辑!
本文将教你:
✅ 基础反向代理配置
✅ 动态 upstream(从注册中心获取)
✅ 主动健康检查
✅ 故障自动剔除
二、基础配置:静态代理单个 Tomcat
场景
- Tomcat 运行在
127.0.0.1:8080 - OpenResty 监听 80 端口
nginx.conf 配置
Lua
http {
upstream tomcat_backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://tomcat_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
✅ 效果 :用户访问
http://localhost/→ 请求转发到 Tomcat
三、进阶 1:多实例负载均衡
配置多个 Tomcat 实例
Lua
upstream tomcat_backend {
# 轮询(默认)
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
# 可选策略
# least_conn; # 最少连接
# ip_hash; # IP 一致性哈希
}
💡 提示:生产环境建议使用内网 IP,避免公网延迟。
四、进阶 2:动态 upstream(从 Consul/Nacos 获取)
静态配置无法应对弹性伸缩。我们用 Lua 动态更新 upstream!
4.1 使用 lua-resty-upstream-healthcheck(推荐)
OpenResty 官方提供模块,支持主动健康检查 + 自动剔除。
安装(通常已内置)
确保编译时包含 lua-resty-upstream-healthcheck(官方包默认包含)。
配置示例
Lua
http {
# 引入健康检查模块
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
# 初始化健康检查
init_worker_by_lua_block {
local healthcheck = require "resty.upstream.healthcheck"
local hc = healthcheck:new({
shm = "healthcheck", -- 共享内存区
upstream = "tomcat_backend",
type = "http",
http_req = "GET /health HTTP/1.0\r\nHost: localhost\r\n\r\n",
check_interval = 2000, -- 每 2 秒检查一次
healthy_threshold = 2, -- 连续 2 次成功标记为健康
unhealthy_threshold = 3, -- 连续 3 次失败标记为不健康
})
hc:start()
}
upstream tomcat_backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
# 注意:这里只写初始节点,后续可动态增删
}
server {
listen 80;
location / {
proxy_pass http://tomcat_backend;
# ... headers
}
}
}
✅ 效果:
- 自动探测
/health接口- 不健康节点自动剔除
- 恢复后自动加回
五、进阶 3:从注册中心动态加载节点(如 Nacos)
若你的 Tomcat 实例注册在 Nacos/Consul,可用 Lua 定期拉取。
示例:从本地文件动态加载(简化版)
Lua
init_worker_by_lua_block {
local ups = require "ngx.upstream"
local timer = ngx.timer
local function update_upstream(premature)
if premature then return end
-- 模拟从文件读取(实际可调 HTTP API)
local file = io.open("/etc/openresty/tomcat_nodes.txt", "r")
if not file then return end
local nodes = {}
for line in file:lines() do
if line:match("^%d+%.%d+%.%d+%.%d+:%d+$") then
table.insert(nodes, line)
end
end
file:close()
-- 更新 upstream
local ok, err = ups.set_primary_peers("tomcat_backend", nodes)
if not ok then
ngx.log(ngx.ERR, "Failed to update upstream: ", err)
end
-- 每 10 秒更新一次
timer.at(10, update_upstream)
end
timer.at(0, update_upstream)
}
📌 生产建议 :调用 Nacos 的
/nacos/v1/ns/instance/listAPI 获取真实节点。
六、关键配置:透传客户端信息
Tomcat 需要知道真实 IP 和协议:
Lua
location / {
proxy_pass http://tomcat_backend;
# 透传关键 Header
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置(重要!)
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
}
✅ Tomcat 中获取真实 IP:
LuaString realIp = request.getHeader("X-Real-IP");
七、故障排查:常见问题解决
❌ 问题 1:502 Bad Gateway
- 原因:Tomcat 未启动或端口不通
- 解决 :检查
telnet 192.168.1.10 8080
❌ 问题 2:静态资源 404
- 原因 :Tomcat 应用 context path 不是
/ - 解决 :
proxy_pass http://tomcat_backend/app/;(注意结尾/)
❌ 问题 3:健康检查误判
- 解决 :确保 Tomcat 提供轻量级
/health接口(返回 200 即可)
八、性能对比:OpenResty vs 直连 Tomcat
| 指标 | 直连 Tomcat | OpenResty 代理 |
|---|---|---|
| QPS(简单接口) | ~3,000 | ~25,000 |
| P99 延迟 | 15ms | 2ms |
| SSL 卸载 | 需 Tomcat 配置 | OpenResty 统一处理 |
| 安全防护 | 无 | WAF、限流、鉴权 |
📊 结论 :OpenResty 不仅不拖慢性能,反而大幅提升吞吐与安全性!
九、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!