Gin服务需配upstream才能实现负载均衡,因proxy_pass直接写死地址仅作单点反向代理;upstream定义服务器组后,proxy_pass引用组名才可分发请求至多实例,并配合健康检查、真实IP透传等保障高可用。

为什么 Gin 服务必须配 upstream 而不能直接 proxy_pass http://127.0.0.1:8080
因为单点 proxy_pass 不构成负载均衡——它只是反向代理。Nginx 要把请求分发到多个 Gin 实例(比如 127.0.0.1:8001、127.0.0.1:8002、192.168.10.5:8001),必须先用 upstream 定义服务器组,再在 proxy_pass 中引用该组名。否则所有流量永远只打到一个端口,起不到扩容或容错作用。
常见错误现象:
– 启动了 3 个 Gin 进程,但 Nginx 日志里只有 127.0.0.1:8001 出现访问记录
– 修改权重后请求分布毫无变化
– 某个 Gin 实例挂了,请求直接 502,没 fallback 到其他节点
- 确保
upstream块定义在http块内(不能嵌套在server里) -
proxy_pass的值必须是http://xxx形式,且xxx是upstream名称,不能带端口或路径(如http://gin_backend/错,http://gin_backend对) - Gin 启动时要显式绑定
0.0.0.0:8001,而非127.0.0.1:8001,否则跨机器或容器无法访问
upstream 里要不要加 ip_hash?Gin 默认无状态,但 session 怎么办
默认不加 ip_hash。Gin 本身不维护会话状态,HTTP 请求天然无状态;但如果你用了基于内存的 session(如 gorilla/sessions 配合 cookiestore),那就必须启用 ip_hash,否则用户刷新页面就登出。
更推荐的做法是:把 session 存到 Redis 或数据库,然后去掉 ip_hash,让轮询或 least_conn 正常工作。这样既保持负载均衡效果,又避免单点故障导致会话丢失。
- 加
ip_hash会破坏负载均衡公平性——同一 IP 永远打固定节点,可能造成某台 Gin 实例过载 - 若用 CDN 或 NAT 网关,
$remote_addr可能全是同一个出口 IP,ip_hash就失效甚至雪崩 - 真正需要粘性会话的场景(如 WebSocket 长连接),应配合
sticky模块(需编译安装)或改用hash $cookie_jsessionid等更可控的 key
proxy_set_header 必须设哪些?Gin 能否拿到真实客户端 IP
必须设 X-Real-IP 和 X-Forwarded-For,否则 Gin 里 c.ClientIP() 返回的是 Nginx 本机地址(127.0.0.1 或内网 IP),不是用户真实 IP。
标准配置如下:
proxy_set_header Host $host;<br>proxy_set_header X-Real-IP $remote_addr;<br>proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br>proxy_set_header X-Forwarded-Proto $scheme;
注意:
– $proxy_add_x_forwarded_for 会在原有 X-Forwarded-For 头基础上追加 $remote_addr,比硬写 $remote_addr 更安全(防伪造)
– Gin 中获取真实 IP 应调用 c.Request.Header.Get("X-Real-IP") 或使用 c.ClientIP()(前提是 Gin 已配置 Engine.RemoteIPHeaders)
– 如果前端还有 LVS 或阿里云 SLB,需额外加 proxy_set_header X-Forwarded-For $http_x_forwarded_for; 并信任对应 header
健康检查怎么配?Gin 的 /health 接口会被 Nginx 频繁调用吗
默认不开启主动健康检查。Nginx 的 max_fails + fail_timeout 是被动检查:只有当请求失败(如超时、502/503)达到阈值,才临时剔除节点。真正的主动探活需用商业版或 OpenResty 的 health_check 指令,或自己加第三方模块。
如果你的 Gin 服务暴露了 /health(返回 200),想让 Nginx 定期探测,目前最稳妥的方式是:用 systemd 或 supervisor 管理 Gin 进程,结合脚本 curl 检查 + 信号重启;或者在 Nginx 外部署 Consul + nginx-upsync-module 动态更新 upstream。
-
max_fails 3 fail_timeout 30s是底线配置,不设等于“挂了也不感知” - 避免把
location /health写进 server 块里被外部访问——这会暴露内部拓扑,建议用internal或仅限内网 IP 访问 - Gin 的
/health不要查 DB 或缓存,否则 Nginx 探活反而压垮后端;只做内存级检查(如return 200 "OK")
upstream 定义位置和 proxy_pass 引用方式——这是最容易写错、也最难排查的一环。


















