Nginx跨机房流量平摊核心是让轮询适配物理拓扑,需结合weight实现机房级分流、upstream_hash保障会话亲和,并通过Lua或nginx-plus动态调权及proxy_next_upstream容错。

用Nginx做跨机房流量平摊,核心不是“加机器”,而是让轮询算法真正适配物理拓扑——否则看似均匀,实则某机房带宽打满、另一机房空转。
轮询不是万能的:看清真实瓶颈在哪
Nginx默认的round-robin只按后端server列表顺序分发请求,不感知网络延迟、机房负载或链路质量。如果两个机房(比如北京IDC和广州IDC)后端节点数相同,但广州机房出口带宽小、RT高,直接轮询会导致大量慢请求堆积在广州节点上,用户感知卡顿,而北京资源闲置。
关键点在于:轮询本身不解决跨地域调度问题,它只是基础分发工具;必须结合权重、健康检查和外部信号(如DNS调度或实时监控)才能落地。
用weight+max_fails实现机房级粗粒度分流
假设北京机房有4台服务器,广州机房有2台,但广州带宽只有北京的60%。可按实际承载能力反向设权:
- 北京每台server设weight=10(总权重40)
- 广州每台server设weight=6(总权重12)
- 同时配max_fails=3 fail_timeout=30s,自动剔除故障节点
这样理论流量比≈40:12 ≈ 77% : 23%,更贴近两机房真实服务能力。注意weight是静态配置,需人工预估,适合业务波动不大的场景。
配合upstream_hash做会话亲和,避免跨机房重定向
若业务有登录态或文件上传依赖本地存储,强制用户固定落在同一机房内很重要。可用$remote_addr或$cookie_session_id做hash:
upstream cluster {
hash $remote_addr consistent;
server bj1.example.com weight=10;
server bj2.example.com weight=10;
server gz1.example.com weight=6;
server gz2.example.com weight=6;
}
consistent参数保证增减节点时大部分客户端仍命中原server,减少会话丢失。此时轮询退居二线,hash成为主路由逻辑,但底层仍靠weight控制各机房整体承接比例。
进阶:用nginx-plus或lua动态调权(轻量级自适应)
纯开源Nginx无法实时读取后端指标,但可通过以下方式补足:
- 用Lua模块(如ngx_http_lua_module)定期调用内部API获取各机房CPU/5xx率,动态修改upstream中server的weight值
- 借助nginx-plus的status API + active health check,自动根据响应时间调整权重(response_time-based load balancing)
- 在前置DNS层做GSLB(如PowerDNS+GeoIP),把北京用户解析到bj.example.com,广州用户解析到gz.example.com,Nginx只负责单机房内轮询——这是更稳妥的解耦方案
不复杂但容易忽略:所有跨机房方案都必须配好proxy_next_upstream,确保单点失败时能快速切到同机房其他节点,而不是跨机房重试增加延迟。










