CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
系统设计入门/课时/负载均衡
RawBlame
课时目录12 节

系统设计入门

  1. 01系统设计是什么
  2. 02性能与扩展基础
  3. 03一致性与 CAP
  4. 04负载均衡
  5. 05缓存模式
  6. 06异步与消息
  7. 07数据架构
  8. 08微服务与网关
  9. 09云设计模式
  10. 10可靠性模式
  11. 11性能反模式
  12. 12综合练习

负载均衡

L4/L7、算法、LB vs 反向代理。

30 分钟

负载均衡

这一课你将能做到

  1. 说清 L4 与 L7 负载均衡的决策依据差异,并能判断本站每条流量该走哪层
  2. 手写一段生产可用的 Nginx upstream 配置(加权、健康检查、故障转移、超时)
  3. 讲透一致性哈希的原理与虚拟节点作用,达到能白板画环的程度

为什么要学

水平扩展加了几台机器后,流量怎么分过去?答案是负载均衡。它还有两个隐藏职责:摘除故障节点(某实例挂了自动不再给它发流量)和滚动发布的执行者(升级时先把一台摘下来,发布完再放回去)。

面试高频三连:「四层和七层负载均衡的区别?」「轮询和一致性哈希分别什么时候用?」「负载均衡器自己挂了怎么办?」——最后一个能答好的人不多,本课一并讲清。

人话:负载均衡就是餐厅领位员。L4 领位员只看「你们几个人」(IP+端口),把人往有空桌的区域引,动作极快;L7 领位员还会问「吃火锅还是西餐」(URL/Header),把你带到对的档口,更聪明但更慢。领位员自己不能是单点,得有两个领位员互为备份。

先建立图像

本站流量分层:

Internet
   │
   │  DNS 轮询 / 云 LB(L4,高吞吐入口,防 LB 单点)
   ▼
Nginx ×2(L7,Keepalived 主备)
   │  按 URL 分流:
   ├── /api/**        → upstream: spring-boot × N
   ├── /judge/**(WS)  → upstream: judge-gateway(ip_hash 保会话)
   └── /static/**     → 本地缓存 / 直接回 CDN

L4 与 L7 对照:

层级决策依据能力性能产品
L4 传输层IP + 端口仅转发 TCP/UDP 流量极高(不解析内容)云 NLB、LVS、DPVS
L7 应用层URL/Header/Cookie路径路由、TLS 终结、限流、改写较高(解析报文)Nginx、ALB、Ingress

判题平台的判断实例:判题机回传结果的内部通道走 L4(纯转发、量大);对用户的 /api/** 走 L7(要做限流、按路径路由到题目服务或判题服务)。

五种算法选型速查:

算法逻辑适用本站场景
Round Robin依次轮转实例同质、请求耗时接近题目列表 API
Weighted RR按权重分流机器配置不齐 / 灰度发布新版本先 10% 流量
Least Connections发给当前连接最少的请求耗时长短不一判题状态轮询(混长短请求)
IP Hash / Cookie同客户端落同实例本地会话兜底WebSocket 判题推送
Consistent Hash哈希环定位节点缓存分片、有状态路由Redis 集群分片(面试最爱)

跟着做

步骤 1:写一段生产可用的 Nginx 配置

# /etc/nginx/conf.d/java-nav.conf
upstream java_nav_api {
    least_conn;                                   # 长短请求混合,选最少连接
    server 10.0.1.11:8080 weight=5 max_fails=2 fail_timeout=10s;
    server 10.0.1.12:8080 weight=5 max_fails=2 fail_timeout=10s;
    server 10.0.1.13:8080 weight=3 max_fails=2 fail_timeout=10s;  # 小机器低权重
    server 10.0.1.14:8080 backup;                 # 备机,前面全挂才启用
    keepalive 64;                                 # 与后端的长连接池,省握手
}

server {
    listen 443 ssl;
    server_name javanav.example.com;

    location /api/ {
        proxy_pass http://java_nav_api;
        proxy_http_version 1.1;
        proxy_set_header Connection "";           # 配合 keepalive
        proxy_set_header X-Real-IP $remote_addr;  # 后端取真实 IP 做限流
        proxy_next_upstream error timeout http_502;  # 失败自动换下一台重试
        proxy_connect_timeout 2s;                 # 连不上快速切节点
        proxy_read_timeout 10s;                   # 读超时兜底
    }
}

逐项解释:max_fails=2 fail_timeout=10s 表示 10 秒窗口内失败 2 次就摘除 10 秒——这就是被动的健康检查;proxy_next_upstream 让单请求失败时自动换节点,用户无感。

步骤 2:验证负载分发与故障转移

# 1. 三个后端日志里各打一行实例名,压测看分发
ab -n 3000 -c 100 http://localhost/api/problems/page/1
# 2. 手动 kill 掉 12 号实例,观察 Nginx error.log 出现
#    "upstream server temporarily disabled",流量自动落在其余两台
# 3. 重启 12 号,10 秒后自动回归轮转

步骤 3:一致性哈希白板推演(面试必画)

普通取模 hash(key) % N 的问题:N 从 3 变 4,几乎所有 key 的落点都变——Redis 分片场景等于全量缓存失效。

一致性哈希把节点和 key 都映射到 0~2^32 的环上,key 顺时针找最近的节点:

        node A            key k1 ──▶ 落 A
       /      \
     k1        k2        环上顺时针:k1→A,k2→B,k3→C
      \        /
  node D ── node B
       \      /
        node C  ◀── key k3

B 宕机:只有落在 B 弧段上的 key 迁移到 C,其余 key 不动(迁移量 1/N)

数据倾斜问题与虚拟节点:物理节点少时弧段不均。给每个物理节点生成 150 个虚拟节点打散在环上,落点统计就均匀了——Redis Cluster 的 16384 slot、Kafka 分区分配都是同一思想。

步骤 4:滚动发布配合优雅下线

发布时的标准动作,LB 是执行者:

# 1. 摘流量:调用 Nginx API 或改 upstream 注释后 nginx -s reload
# 2. 等待实例处理完存量请求(Spring Boot 配置)
server.shutdown: graceful          # 优雅停机,等线程处理完再退出
spring.lifecycle.timeout-per-shutdown-phase: 30s
# 3. 发新版 → 健康检查通过 → 放回流量 → 下一台

不配 graceful 的后果:实例收到 SIGKILL 时正在处理的请求全部 502——发布高峰期的报错大多是这个原因。

讲清楚要点

  1. L4 看地址、L7 看内容:需要按 URL/用户分流、终结 TLS、做应用层限流就是 L7;纯粹转发大流量(内部 RPC、消息通道)用 L4 更快。两层常串联:云 LB(L4) → Nginx(L7) → 实例。
  2. 算法跟着「请求耗时是否均匀」选:耗时均匀轮询即可;长短请求混合(判题状态轮询)用最少连接,否则快实例会被慢请求连累排队。
  3. 一致性哈希的核心价值是「增减节点只迁移 1/N」:用于有状态数据的分片路由(Redis 集群、分布式缓存),无状态 HTTP 转发用不上它,别在 API 负载均衡上硬套。
  4. 健康检查分被动和主动:Nginx 开源版被动(靠失败计数摘除),商业版/云 LB 主动探测(定时打 /actuator/health)。探活间隔要小于故障感知要求,又不能太密打挂后端。
  5. LB 自己不能是单点:Nginx 主备 + Keepalived 虚拟 IP 漂移,或直接用云厂商多可用区 LB。面试答「LB 挂了怎么办」就答这两条。

你可能会懵的地方

  • 负载均衡、反向代理、API 网关是一回事吗? 反向代理是「替后端接收请求」,负载均衡是它的能力之一;API 网关在反向代理之上叠加鉴权、限流、聚合、协议转换。Nginx 可以三者都做,Spring Cloud Gateway 专注网关层。区别在职责,不在产品。

  • 为什么判题 WebSocket 要会话保持? WS 是长连接,握手后状态留在建立连接的那台实例上。ip_hash 能保住会话,但宕机会断线——更好的做法是 WS 网关 + Redis 广播消息,让任何实例都能处理。

  • Nginx 和 LVS 什么关系,为什么大厂两层都用? LVS 工作在内核态 L4,单机转发能力远超 Nginx;Nginx 工作在用户态 L7,功能丰富。经典架构 LVS 做第一层扛量,Nginx 做第二层做路由。小流量用云 LB + Nginx 两层足够。

  • 一致性哈希和 Redis Cluster 的 slot 方案哪个好? 思想同源(都是减少扩缩容时的迁移量)。slot 方案把哈希空间预切成 16384 份再分配给节点,运维更直观、迁移粒度可控;一致性哈希更通用但需要虚拟节点调参。面试说清两者同属「哈希分片 + 减少再平衡成本」即可。

  • 健康检查间隔设多少合适? 常见 25 秒、连续 23 次失败才摘除。太密会误杀(瞬时 GC 停顿被当故障),太疏故障感知慢。配合重试机制(proxy_next_upstream)可以把感知压力转给请求级故障转移。

错法对照

错法问题正解
所有请求 Round Robin 一把梭长短请求混合时快实例空转、慢实例压垮Least Connections 或按耗时分类路由
用 ip_hash 做 API 会话保持节点宕机全员断线、负载倾斜会话放 Redis,无状态转发
健康检查只探端口不探业务进程活着但 DB 连不上照样接流量探 /actuator/health(含 DB/Redis 依赖项)
后端实例配了 keepalive,Nginx 没配每请求新建 TCP,延迟和端口浪费proxy_http_version 1.1 + Connection ""
发布直接 kill -9存量请求全部 502graceful shutdown + 先摘流量

卡点急救

  1. 某实例反复被摘又恢复(抖动):多半是它真有问题——看该实例的 GC 日志和线程池,长尾停顿触发失败计数;也可能 Nginx 与它之间网络抖动,检查同机房路由。
  2. 流量分配严重不均:检查机器规格是否一致(不一致该上权重);开启了 least_conn 但后端有长连接任务占着连接数;或用了 ip_hash 而某几个大客户 IP 流量占比过高。
  3. 发布后部分请求 502:确认三点——旧实例是否 graceful 停机、Nginx 是否等旧连接排空(worker_shutdown_timeout)、新实例是否先过健康检查再放量。标准流程是摘流量→排空→重启→探活→回流量。

面试常问

  • 四层和七层负载均衡的区别,分别举应用场景? L4 基于 IP+端口转发(不解析应用层),性能高,用于 TCP 大流量、数据库代理、LB 的最外层;L7 解析 HTTP(URL/Header/Cookie),能做路径路由、限流、灰度,用于业务入口。可举本站例子:内部判题结果通道 L4,用户 API 入口 L7。

  • 一致性哈希原理?虚拟节点解决什么问题? 哈希环 + 顺时针最近节点,节点增减只影响相邻弧段(迁移 1/N);虚拟节点把每个物理节点打散成上百个环上点,解决节点少导致的负载倾斜,同时提升节点数变化时的平滑度。应用:Redis Cluster slot 思想同源、分布式缓存路由、Kafka 消费者分配。

  • 负载均衡器本身挂了怎么办? 三层答案:① 主备 + Keepalived/VRRP 虚拟 IP 自动漂移;② 云环境直接用多可用区托管 LB;③ DNS 层再兜底(多 LB 记录 + 健康检查摘除)。核心思想:任何一层都要消除单点,LB 也不例外。

自测三问

  1. 题目列表 API 和判题 WebSocket 推送分别该用什么算法?为什么?
  2. N=4 时节点从 4 扩到 5,普通取模和一致性哈希分别迁移多少 key?
  3. graceful shutdown 没配置时,滚动发布会出现什么现象?完整发布流程应该是怎样的?

小结一句话

负载均衡让水平扩展真正可用——选对层级(L4/L7)与算法(RR/最少连接/一致性哈希),探活摘除与优雅下线是稳定性的另一半。

延伸

  • Nginx 官方文档 — upstream 模块:本课配置所有参数的权威说明
  • Consistent Hashing(Karger et al. 原论文):一致性哈希出处
  • Keepalived 官方文档:LB 高可用主备方案
  • 下一课:缓存模式——读路径的第一杠杆,Cache-Aside 三兄弟与穿透/击穿/雪崩全解。
加载本节练习…
← 上一课一致性与 CAP下一课 →缓存模式