策略、健康检查与效果验证
策略 1:轮询(Round Robin)
轮询是最容易解释、也最容易验证的策略:只要后端实例规格相同,它就能把流量切成等份。这一节先把它配好,作为后面三种策略的对照组——只有先有基准,后面的收益才说得清楚。
策略 1:轮询(Round Robin):流量配置
- 步骤 1:把同一组后端实例写进同一个 upstream 组,构成可轮询的候选列表
- 步骤 2:让 Nginx 按 round-robin 顺序把每个新请求依次分给列表中的下一台实例
- 步骤 3:压测并核对各实例收到的请求数,确认差距不超过预期误差
- 步骤 4:扩容或缩容后重载配置,轮询序列按新的实例列表重新开始
关注点:请求在实例间是否均匀分摊,以及轮询序列与后端列表是否一致。
请求分布:
请求 1 → Server 1
请求 2 → Server 2
请求 3 → Server 3
请求 4 → Server 4
请求 5 → Server 1
...
策略 2:最少连接(Least Connections)
轮询只看次数,看不见快慢。而股票、天气这类接口耗时差异明显,固定均分反而让慢实例被压垮。最少连接把「当前压力」引入分配依据:谁的连接少,下一个请求就给谁。
策略 2:最少连接(Least Connections):流量配置
- 步骤 1:采集每个后端实例当前的活跃连接数,作为本次分配的依据
- 步骤 2:在 upstream 中启用 least_conn,把请求发给当前连接数最少的实例
- 步骤 3:用耗时差异大的接口压测,观察慢实例是否自动少分了请求
- 步骤 4:某个实例响应明显变慢时把它从 upstream 摘除,避免拖住后续请求
关注点:慢请求会不会被摊开,以及连接数计数是否会被长连接拖住。
优势:
- 将请求分配给当前连接数最少的服务器
- 适合处理时间差异大的场景
策略 3:IP 哈希(IP Hash)
有状态的业务要求同一用户的请求回到同一台机器,IP 哈希就是最省事的做法。它把「客户端地址」变成分配依据,代价是分布完全由地址决定,一旦大量用户来自同一个出口,倾斜就会很明显。
策略 3:IP 哈希(IP Hash):流量配置
- 步骤 1:确认客户端有稳定可哈希的来源地址,并取 X-Forwarded-For 的第一跳
- 步骤 2:用 hash $remote_addr consistent 开启哈希,保证同一 IP 始终落到同一实例
- 步骤 3:在带 NAT 出口的压测环境验证,确认流量是否集中在少数实例上
- 步骤 4:出现倾斜时改用 consistent 参数,扩容时只重分布受影响的 key
关注点:同一客户端能否稳定命中同一实例,以及哈希倾斜会不会让少数机器过载。
优势:
- 同一个 IP 的请求总是分配到同一台服务器
- 适合有状态的服务
- 问题:可能导致负载不均
策略 4:加权轮询(Weighted Round Robin)
轮询默认所有机器一样强,可实际部署里常常混着高配和低配。加权轮询让容量差异直接写进配置:权重 60 的机器就接走六成流量,扩容时也按这个比例去扩。
策略 4:加权轮询(Weighted Round Robin):流量配置
- 步骤 1:统计各实例的 CPU 核数与实测容量,按比例折算成权重
- 步骤 2:在 upstream 中给每台实例配置 weight,并保持权重总和为 100
- 步骤 3:压测核对每台机器实际分到的流量比例是否与权重一致
- 步骤 4:机器更换规格后调整权重并重载配置,避免高配实例反而成为瓶颈
关注点:异构机器的容量差异是否被权重如实表达。
请求分布:
请求 1 → Server 1
请求 2 → Server 1
请求 3 → Server 1
请求 4 → Server 2
请求 5 → Server 2
请求 6 → Server 3
请求 7 → Server 3
请求 8 → Server 4
...
Nginx 被动健康检查
被动健康检查不额外发探测流量,完全依赖真实请求的成败。好处是零额外开销,坏处是低流量接口可能很久都发现不了故障——所以它必须和主动检查一起看。
Nginx 被动健康检查:流量配置
- 步骤 1:在 upstream 中为每个后端配置 max_fails 与 fail_timeout 两个参数
- 步骤 2:由真实业务请求累计失败次数,连续失败达到阈值即标记为不可用
- 步骤 3:观察失败实例是否被跳过,请求是否自动转移到健康实例
- 步骤 4:fail_timeout 到期后重新尝试连接,恢复则重新加入转发序列
关注点:故障实例被摘除的速度,以及恢复探活的时间窗口。
参数说明:
max_fails=3:30 秒内失败 3 次,标记为不可用fail_timeout=30s:30 秒后重新尝试连接
主动健康检查(需要第三方模块)
主动检查由 Nginx 定时去问后端一句「你还好吗」,答案不依赖有没有人访问你。所以低频接口和空闲实例也能被及时发现,代价是要额外引入第三方模块。
主动健康检查(需要第三方模块):流量配置
- 步骤 1:安装支持主动检查的第三方模块,确认 Nginx 能正常编译加载该模块
- 步骤 2:配置 health_check 指令,设定检查间隔、超时时间与健康判定路径
- 步骤 3:观察探测请求的返回码与耗时,确认异常实例被标记为 down
- 步骤 4:上游恢复后自动切回健康实例,探测流量与业务流量分开统计
关注点:空载实例能否被及时发现,以及探测失败与真实故障如何区分。
前面四种策略都把请求当成无状态的,一旦业务需要记住「这个用户是谁」,就必须想办法让同一个用户的请求回到同一台机器。会话保持的做法不止一种,各自的失效场景也不一样。
如果需要会话保持(同一用户的请求总是分配到同一台服务器):
会话保持:流量配置
- 步骤 1:确认业务把会话状态放在实例本地,而不是依赖共享存储
- 步骤 2:用 IP 哈希把同一客户端的请求固定转发到同一台实例
- 步骤 3:登录后连续请求验证会话未失效,并压测确认没有实例过载
- 步骤 4:实例下线时会话随之失效,需要准备重新登录或共享存储兜底
关注点:有状态会话能否稳定落到同一实例,以及实例故障时的会话迁移代价。
或者使用 cookie:
cookie 的粘性不依赖客户端地址,代理、CDN 之后也能生效。它的代价是把后端拓扑暴露给了客户端,也多了一处可能被伪造的地方,所以必须校验签发方,并留好后端挂掉后的重新分配路径。
会话保持:流量配置
- 步骤 1:由负载均衡器在首次访问时给客户端下发带后端标识的 cookie
- 步骤 2:后续请求按 cookie 中的标识直接转给对应的那个实例
- 步骤 3:校验 cookie 是否由本集群签发,防止被伪造到任意实例
- 步骤 4:后端实例不可用时清除 cookie,把请求重新分配给健康实例
关注点:粘性 cookie 的签发与信任边界,以及后端失效后的回退路径。
上线后,我观察了一周:
性能提升
负载均衡后(4 台服务器):
- 总 QPS:60
- 每台 QPS:15
- 响应时间:100ms
- 每台 CPU 使用率:40%
可用性提升
单机时代:
- 服务器故障 → 全站不可用
- 恢复时间:重启服务器(5-10 分钟)
负载均衡后:
- 1 台服务器故障 → 其他服务器继续服务
- 影响范围:25% 的用户(如果有 4 台服务器)
- 恢复时间:自动检测并恢复流量(30 秒)
策略配得再对,也需要数据来证明它在起作用。这一节把监控落到实例维度:只有能看出「流量到底分到了哪台机器」,才能在用户投诉之前发现倾斜和摘除。
监控和告警
- 步骤 1:采集每个后端实例的请求数、活跃连接数、错误率与响应延迟
- 步骤 2:按实例维度对比 QPS 分布,判断是否存在负载倾斜或单机瓶颈
- 步骤 3:为错误率突增、实例失联和连接数打满配置分级告警
- 步骤 4:告警触发后核对 upstream 状态,确认摘除与流量转移已经生效
关注点:实例级流量是否可见,以及摘除动作能否第一时间被感知。
练习 1
现在有 4 台应用服务器,其中 1 台配置更高,另外 3 台配置相同。你会选择哪种负载均衡策略?上线后至少观察哪些指标?
解题思路:
选策略要看实例是否同构:配置有差异时,加权轮询是最直接的选择。上线后的观察要覆盖三个维度——负载是否按权重分摊、用户体验是否真的变好、故障摘除是否生效。
详细步骤:
可以先选加权轮询。配置更高的服务器承担更多请求,其余服务器继续分担基础流量。
上线后重点看三类指标:
- 实例负载是否均衡:每台服务器的 QPS、CPU、内存、连接数是否符合权重预期。
- 用户体验是否变好:整体响应时间、P95/P99 延迟、错误率是否下降。
- 故障摘除是否有效:主动或被动健康检查能不能及时发现异常实例,摘除后流量是否自动转移。
如果高配服务器反而成为瓶颈,就要降低它的权重;如果业务请求耗时差异很大,可以再考虑最少连接策略。
最终答案:
选加权轮询,让高配实例承担更多请求。上线后至少观察三类指标:各实例的 QPS、CPU、内存、连接数是否符合权重预期;整体响应时间、P95/P99 延迟与错误率是否下降;健康检查能否及时发现并摘除异常实例、流量是否自动转移。若高配实例反成瓶颈就降低其权重,请求耗时差异大时可再考虑最少连接数。
发现内容有问题?
告诉我们哪里需要改进。
