gin本身不处理负载均衡,nginx才是真正的负载分发组件;gin只需无状态监听本地端口,所有负载逻辑均由nginx的upstream和proxy_pass实现。

直接说结论:Gin 本身不处理负载均衡,Nginx 才是真正做负载分发的组件;Gin 只需保持无状态、监听本地端口,剩下的全交给 Nginx 的 upstream 和 proxy_pass 配置。别在 Gin 里写“负载均衡逻辑”,那是方向性错误。
upstream 定义后端 Gin 实例时的 server 参数细节
你得把每个运行 Gin 的服务实例(比如 192.168.1.10:8080、192.168.1.11:8080)写进 upstream 块里,但参数不是随便加的:
-
weight要按实际 CPU/内存配比设,比如新机器配weight=5,旧机器配weight=2,别图省事全用默认 1 -
max_fails=3 fail_timeout=30s必须配,否则某台 Gin panic 后 Nginx 还会持续转发请求,导致用户看到 502 - 别用
backup或down临时下线节点——它们不触发健康检查重试逻辑,容易卡死;要用down仅限维护窗口期手动摘除 - 如果 Gin 实例跑在 Docker 里且用 host 网络,IP 写宿主机地址;用 bridge 网络,IP 得是容器在 docker0 网桥上的真实 IP,不是
localhost
proxy_pass 转发时必须带的 header 项
Gin 默认从 $remote_addr 取客户端真实 IP,但 Nginx 代理后这个值会变成 Nginx 自己的内网 IP。不加 header,Gin 日志和限流都会失效:
- 必须加
proxy_set_header X-Real-IP $remote_addr;—— 这是原始客户端 IP - 必须加
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;—— 支持多层代理链路 - 建议加
proxy_set_header Host $host;—— 防止 Gin 生成的跳转链接漏掉域名 - 别漏掉
proxy_set_header Connection '';—— 否则 HTTP/1.1 keepalive 在 upstream 侧可能被关闭
ip_hash 导致 Gin 会话粘滞的边界问题
用 ip_hash 确保同一 IP 总打到同一台 Gin 实例,适合没接入 Redis 共享 session 的老项目。但要注意:
- IPv4 下只取前 24 位哈希,NAT 环境(比如公司出口、校园网)会导致几十人挤在同一台 Gin 上
- 客户端换 Wi-Fi 或切 4G/5G,IP 变了,session 就断——这不是 Nginx 的 bug,是算法固有限制
- 增减 Gin 实例数时,整个哈希环重排,所有用户都会被重新分配,会话批量丢失
- 真要会话保持,优先改 Gin 用 JWT 或 Redis Store,而不是依赖
ip_hash
least_conn 在长连接场景下的实际效果
如果你的 Gin 接的是 WebSocket 或 gRPC 流式接口,连接生命周期远长于 HTTP 请求,least_conn 比轮询更合理:
- 它统计的是当前活跃连接数(not request count),所以对长连接敏感
- 但注意:Nginx 统计的是它自己跟 Gin 之间的 TCP 连接数,不是 Gin 应用层的 goroutine 数
- 如果 Gin 用了连接池(比如数据库连接),
least_conn对后端资源压力缓解有限,得配合应用层限流 - 别和
ip_hash同时用——Nginx 会忽略least_conn,只认ip_hash
最易被忽略的一点:Nginx 的 upstream 健康检查是被动的,只有流量进来才会触发探测;没流量时故障节点不会自动恢复。生产环境务必搭配主动健康检查模块(nginx-plus)或外部探活脚本,否则凌晨出问题没人发现。











