Nginx 负载均衡:5 种算法 + 生产配置
一句话结论(30s)
Nginx 五种负载均衡算法各有适用场景——因为轮询适合后端均等、加权轮询用平滑算法避免打桩、IP 哈希保持会话、URL 一致性哈希最小化缓存失效、最短时间适合性能差异大,所以选型取决于后端是否同质、是否有状态、是否有本地缓存。
核心原理(2min)
- 轮询(默认):依次均匀分发,适合后端性能相同。
- 加权轮询:按
weight分配,用平滑算法动态计算currentWeight让高权重节点分散出现,避免连续打同一台。 - IP 哈希(
ip_hash):同一客户端 IP 恒路由到同一后端,适合有状态服务,但扩缩容会重新分布、Session 失效。 - URL 哈希(
hash $request_uri consistent):同一 URL 走同一后端,适合本地缓存热点;consistent一致性哈希在扩缩容时只影响相邻段。 - 最短时间(
least_time,商业版):选响应最快后端,适合性能差异大/负载不均。 - 健康检查:
max_fails/fail_timeout标记故障节点,proxy_next_upstream重试需设上限防故障放大。
底层深入(5-10min)
5 种算法
1. 轮询(Round Robin,默认)
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
请求依次均匀分发。适合所有后端性能相同的场景。
2. 加权轮询(Weighted Round Robin)
upstream backend {
server 192.168.1.10:8080 weight=3; # 新机器,性能好,多分
server 192.168.1.11:8080 weight=1; # 老机器,少分
}
Nginx 加权轮询使用平滑算法——不是简单按权重轮流(3→1→3→1…),而是动态计算 currentWeight,让高权重节点分散出现,避免”打桩”效应(连续 3 次打到同台机器)。
想一想:为什么加权轮询要用平滑算法? 因为如果按权重机械地”3 次 A → 1 次 B”循环,高权重节点会连续被打桩 3 次,瞬时负载不均;平滑算法动态维护每个节点的
currentWeight,让高权重节点”分散地、穿插地”多出现几次,最终比例仍符合权重,但任意时刻的负载都更均匀——这是”长期公平”和”瞬时均衡”的兼得。
3. IP 哈希(IP Hash)
upstream backend {
ip_hash;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
同一客户端 IP 的请求始终路由到同一后端。适合有状态服务(Session 非共享),但后端扩缩容时哈希重新分布、部分用户 Session 丢失。
想一想:为什么 IP 哈希在扩缩容时会 Session 失效? 因为路由规则是
hash(客户端 IP) % 节点数,节点数一变,取模结果全变了,大量用户的请求会被路由到另一台机器,原来那台上的 Session 就”找不到了”。所以 IP 哈希适合节点数稳定的场景,频繁扩缩容要用一致性哈希或共享 Session。
4. URL 哈希(Hash)
upstream backend {
hash $request_uri consistent;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
同一 URL 走同一后端——适合后端有本地缓存热点 URL 的场景。consistent 关键字启用一致性哈希,扩缩容时只影响相邻段的数据,最小化缓存失效。
想一想:为什么一致性哈希扩缩容只影响相邻段? 因为它把哈希值映射到一个环上,每个节点占据环上的一段;增删一个节点,只把”它相邻那一段”的数据重新分配,其他大部分数据仍在原节点。相比取模法”一改全乱”,一致性哈希把缓存失效的范围从”全部”缩小到”一小段”,这正是
consistent关键字的价值。
5. 最短响应时间(Least Time)
upstream backend {
least_time header;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
Nginx Plus(商业版)特性。选择当前响应时间最短的后端。适合后端性能差异大或负载不均匀的场景。
健康检查 + 故障转移
upstream backend {
server 192.168.1.10:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
location /api/ {
proxy_pass http://backend;
proxy_next_upstream error timeout http_500 http_502 http_503;
proxy_next_upstream_tries 2; # 最多重试 2 个后端
proxy_next_upstream_timeout 5s; # 重试总超时 5 秒
}
max_fails=3 fail_timeout=30s:30 秒内连续 3 次失败 → 标记为 down → 30 秒后重试。
proxy_next_upstream:当返回 error/timeout/5xx 时自动重试下一个后端。重试次数和超时都要设置上限——无限重试会放大故障。
想一想:为什么故障重试要设上限? 因为如果第一个后端挂了、重试又打到另一个也慢的后端,再重试、再重试……一个请求的耗时会被无限放大,反而把本已脆弱的系统压得更狠。设置
proxy_next_upstream_tries和超时,等于给”自动重试”加上熔断,防止故障被重试放大成全链路雪崩。
总结
| 算法 | 适用场景 | 限制 |
|---|---|---|
| 轮询 | 后端性能均等 | 不考虑负载差异 |
| 加权轮询 | 后端性能不均 | 需要手动配权重 |
| IP 哈希 | 有状态服务 | 扩缩容 Session 失效 |
| URL 哈希 | 本地缓存场景 | 热点 URL 负载不均 |
| 最短时间 | 性能差异大 | 商业版特性 |
章末提问
Q1:加权轮询为什么要用平滑算法,不平滑会怎样?
结论先行:不平滑会出现”打桩”效应——高权重节点被连续命中多次,瞬时负载不均。
因为按权重机械循环(如 3:1 就是 A、A、A、B),高权重机器会连续承接多次请求,某一瞬间被打满。平滑算法动态维护 currentWeight,让高权重节点穿插出现,长期比例仍符合权重,但任意时刻的负载都更均匀。
Q2:IP 哈希有什么缺点?什么场景适合用?
结论先行:缺点是扩缩容会导致哈希重分布、大量 Session 失效;适合”有状态且节点数稳定”的场景。
因为路由是 hash(客户端 IP) % 节点数,节点数一变取模结果全变,用户被路由到新机器,旧 Session 丢失。所以它适合需要”同一用户始终打到同一台、且后端很少增减”的场景;频繁扩缩容应改用一致性哈希或共享 Session。
Q3:一致性哈希为什么能最小化缓存失效?
结论先行:因为它把节点映射到哈希环上,增删节点只影响相邻一段,而不是像取模法那样全部重排。
因为每个节点只负责环上的一段区间,新增/下线一个节点,只需把相邻区间的数据重新分配,其他大部分数据仍在原节点、缓存继续命中。相比 hash % N 的”一改全乱”,一致性哈希把失效范围从”全部”缩到”一小段”。