Files
test-repo/docs/zh-cn/appendix/load-balancing.md
T
sanbuphy 7c70c37072 feat(docs): add interactive demo components for technical appendices
Add placeholder Vue components for visualizing technical concepts across multiple domains including frontend routing, browser rendering, cache design, queue design, database principles, API design, cloud services, and backend evolution. These components provide interactive educational content for the documentation.

Update documentation structure to include new appendix sections and enhance existing content with visual components. Remove unused 'codex' dependency from package.json.
2026-02-06 03:34:50 +08:00

22 KiB
Raw Blame History

负载均衡与多实例部署示意图

💡 学习指南:本文将带你理解现代分布式系统中,如何通过负载均衡技术把流量"聪明地"分配到多个服务器实例上。我们会从四层/七层负载均衡讲起,逐步深入到健康检查、会话保持、自动扩缩容,最后到异地多活部署。建议你先阅读 后端架构演进 了解基本概念。

在开始之前,建议你先补充两块"基础砖":

  • 网络基础:可以先阅读 网络基础概念 了解 TCP/IP、HTTP 等协议。
  • 容器与编排:如果你还不熟悉 Docker 和 Kubernetes,可以先看 容器化部署

0. 引言:当一台服务器扛不住的时候

想象你开了一家网红奶茶店。刚开业时,店里只有一个收银台,顾客排队点单,一切井然有序。但随着口碑传播,排队的人越来越多,一个收银台根本应付不过来——顾客等得不耐烦,抱怨连连,甚至有人转身离开。

这时候你有两个选择:

  1. 换一台更快的收银机(垂直扩展):但再快的机器也有极限,而且贵得离谱。
  2. 多开几个收银台,让顾客分流(水平扩展):每个收银台处理一部分顾客,整体效率大幅提升。

负载均衡(Load Balancing)就是第二个方案的"总指挥"。 它站在所有收银台前面,帮顾客决定:"你去1号台,你去2号台..." 确保每个收银台的 workload 相对平均,不让任何一个台累垮。


1. 负载均衡器的"分层": L4 vs L7

就像快递分拣有"只看邮编"和"检查包裹内容"两种策略,负载均衡也分不同"层次":

1.1 四层负载均衡(L4):"只看门牌号"

工作在传输层(TCP/UDP,就像快递小哥只看你家的门牌号(IP地址+端口号),不关心你家是做什么的。

特点:

  • 速度超快:只做简单的地址转发,不解析数据包内容
  • 适用场景:数据库连接、Redis缓存、长连接游戏服务器
  • 代表产品LVSLinux Virtual Server)、AWS NLB、Azure Load Balancer

真实案例:电商大促的流量入口

某头部电商在双11期间,使用L4负载均衡处理每秒数百万的TCP连接。由于L4不解析HTTP内容,处理速度极快,确保用户在秒杀开始瞬间就能建立连接,不因为负载均衡本身的处理延迟而错过抢购。

1.2 七层负载均衡(L7):"检查包裹内容"

工作在应用层(HTTP/HTTPS,就像快递小哥不仅看门牌号,还会打开包裹检查内容,根据内容决定怎么送。

特点:

  • 智能路由:可以根据URL路径、HTTP头、Cookie等做精细化路由
  • 高级功能:SSL卸载、内容缓存、压缩、安全WAF
  • 适用场景Web应用、API网关、微服务架构
  • 代表产品Nginx、HAProxy、AWS ALB、Envoy

真实案例:SaaS平台的多租户路由

某SaaS公司使用Nginx作为L7负载均衡,根据HTTP Header中的X-Tenant-ID将不同租户的数据请求路由到对应的数据库集群。tenant-a 的请求去 db-cluster-1tenant-b 的请求去 db-cluster-2,实现了完全的数据隔离。

1.3 L4 vs L7 对比一览

维度 四层负载均衡 (L4) 七层负载均衡 (L7)
工作层级 传输层 (TCP/UDP) 应用层 (HTTP/HTTPS)
决策依据 IP地址 + 端口号 URL、Header、Cookie、Body
处理速度 极快(内核态处理) 较快(用户态解析)
功能丰富度 基础转发 SSL卸载、缓存、压缩、WAF
典型场景 数据库、游戏、长连接 Web应用、API网关、微服务
代表产品 LVS、AWS NLB Nginx、HAProxy、AWS ALB

2. 健康检查:别让"坏掉"的服务器继续接客

想象一下,你的某个收银台突然坏了,但顾客不知道,还在源源不断地排过去。结果队伍越来越长,顾客怨声载道。

健康检查(Health Check)就是防止这种情况发生的"哨兵"。 它定期"体检"每台服务器,发现"生病"的立即从队列中移除,等"康复"了再请回来。

2.1 主动健康检查 vs 被动健康检查

主动健康检查(Active Health Check:负载均衡器主动"敲门"问服务器"你还在吗?"

  • 定期发送探测请求(如 HTTP /health、TCP ping
  • 响应超时或返回错误码则认为不健康
  • 优点:检测结果准确可靠
  • 缺点:产生额外的探测流量

被动健康检查(Passive Health Check:负载均衡器"观察"真实业务流量的响应情况

  • 统计实际请求的响应时间、错误率
  • 连续多次失败则认为不健康
  • 优点:不产生额外流量
  • 缺点:需要足够的流量样本才能判定

2.2 阈值设定:别让"小病"也触发告警

健康检查的阈值就像体温计:37度是正常,38度是低烧,40度是高烧。

常见的阈值配置:

指标 健康阈值 不健康阈值 说明
HTTP 状态码 200-399 400+ 或超时 4xx/5xx 都认为失败
TCP 连接 成功建立 连接超时 检查端口是否可达
响应时间 < 500ms > 2000ms 超时时间通常设为2-5s
连续失败次数 - 3次 避免单次抖动误判
检查间隔 - 5s 太频繁会增加负载

踩坑经验:阈值设置太"敏感"的教训

某团队将健康检查的响应时间阈值设为 100ms,而他们的应用平均响应时间在 80-120ms 之间波动。结果是服务器频繁被标记为"不健康",导致流量在健康和不健康之间反复横跳,系统整体可用率反而下降。

正确的做法: 阈值应该设置为P99 响应时间的 2-3 倍,给正常波动留出足够的缓冲空间。


3. 会话保持:让"老顾客"一直找同一个"收银员"

想象你是奶茶店的常客,每次来都由同一个店员接待。她知道你的口味偏好(半糖、去冰),服务起来又快又贴心。但如果每次来都换一个新人,你得一遍遍重复同样的要求,效率大打折扣。

会话保持(Session Persistence/Sticky Session 就是解决这个问题的方法:确保同一个用户的请求,始终被路由到同一台后端服务器。

3.1 三种会话保持机制对比

机制 实现原理 优点 缺点 适用场景
Cookie 插入 LB在响应中插入Cookie,后续请求携带此Cookie 不受IP变化影响,首次请求即可保持 客户端需支持Cookie,可能被禁用 电商购物车、登录态保持
IP 哈希 对客户端IP做哈希计算,映射到特定服务器 无需客户端支持,无状态 IP变化会丢失会话,难以均匀分布 无Cookie环境、WebSocket
粘性会话表 LB维护会话到服务器的映射表 支持会话复制和故障转移 占用LB内存,需要额外同步 高可用要求严格的场景

3.2 真实案例:电商大促期间的会话保持策略

某电商平台在大促期间面临以下挑战:

  1. 购物车数据需要保持:用户可能跨多个页面添加商品,需要保证请求都落在同一台服务器,购物车数据才能正确累计。

  2. 秒杀场景下服务器动态扩容:大促期间服务器数量从平时的10台动态扩展到50台。

  3. 部分服务器可能故障:需要能够快速剔除故障节点,同时不影响用户会话。

他们的解决方案

  1. 采用 Cookie 插入机制:负载均衡器(Nginx)在首次响应时设置 SERVERID Cookie,值为后端服务器的唯一标识。

  2. 会话表持久化:将会话映射表存储在 Redis 集群中,即使某台 Nginx 重启,也能从 Redis 恢复会话映射关系。

  3. 故障转移策略:当后端服务器健康检查失败时,将其从可用列表移除。对于已经绑定到该服务器的会话,下次请求时重新哈希分配到新的健康节点(牺牲一次会话保持,换取服务可用性)。


4. 部署策略:蓝绿部署与金丝雀发布

当新版本上线时,如何确保零停机?当新版本有 Bug 时,如何快速回滚?这涉及到两种经典的部署策略。

4.1 蓝绿部署:"一键切换"的零停机发布

核心思想:同时维护两套完全相同的生产环境(蓝环境和绿环境),但只有一个环境对外提供服务。

工作流程

  1. 初始状态:蓝环境运行 v1.0(生产),绿环境待命。

  2. 部署新版本:在绿环境部署 v1.1,进行内部冒烟测试。

  3. 切换流量:将负载均衡器指向绿环境,流量瞬间切换到 v1.1。

  4. 监控观察:观察绿环境运行状态,确认无异常。

  5. 保留旧版本:蓝环境保持 v1.0 一段时间(如24小时),作为快速回滚的保险。

优缺点分析

优点 缺点
零停机时间,切换在毫秒级完成 资源成本高,需要同时维护两套环境
快速回滚,发现问题立即切回原环境 数据库Schema变更时需要特别处理兼容性
新环境可完整测试后再接管流量 不适用于有状态服务(如WebSocket长连接)

适用场景

  • 对可用性要求极高的金融、电商核心交易系统
  • 需要频繁发布但无法接受停机的 SaaS 服务
  • 有充足的硬件/云资源预算

4.2 金丝雀发布:"小步快跑"的灰度策略

金丝雀发布得名于历史上的"煤矿金丝雀"——矿工带着金丝雀下井,如果金丝雀出现异常,说明有毒气体泄漏,矿工立即撤离。在软件发布中,金丝雀发布就是先让一小部分用户试用新版本,观察没有问题后再逐步扩大范围。

核心思想

  1. 小流量先行:先将 1% 的流量导入新版本服务器。

  2. 观察指标:持续监控错误率、延迟、业务关键指标。

  3. 逐步放量:如果一切正常,逐步将比例提升到 5%、10%、25%、50%、100%。

  4. 快速回滚:一旦发现异常,立即将所有流量切回旧版本。

金丝雀发布的优势:

优势 说明
🎯 风险可控 即使新版本有严重 Bug,也只影响少量用户
📊 真实验证 在真实生产环境验证,比测试环境更可靠
🚀 快速迭代 团队可以更自信地频繁发布新功能
💰 资源友好 不需要像蓝绿部署那样准备两套完整环境

金丝雀发布的典型流量分配策略:

阶段 1 (5分钟):   1%  新版本  → 99% 旧版本
阶段 2 (15分钟):  5%  新版本  → 95% 旧版本
阶段 3 (30分钟):  10% 新版本  → 90% 旧版本
阶段 4 (1小时):   25% 新版本  → 75% 旧版本
阶段 5 (2小时):   50% 新版本  → 50% 旧版本
阶段 6 (全量):    100%新版本

注意:每个阶段都需要持续监控关键指标,只有确认无异常后才进入下一阶段。


5. 自动扩缩容:让系统自己"呼吸"

想象你开了一家餐厅。午餐高峰期需要10个服务员,但下午3点闲时只需要2个。如果一直维持10个人,人工成本爆炸;如果一直只有2个人,高峰期顾客等得不耐烦全跑了。

自动扩缩容(Auto Scaling)就是让系统像餐厅一样"灵活排班"——忙的时候自动加服务器,闲的时候自动减服务器。

5.1 扩容指标的选择

自动扩缩容的核心是回答一个问题:什么时候该加机器?什么时候该减机器?

常见的决策指标:

指标 扩容阈值 缩容阈值 适用场景
CPU 使用率 > 70% < 30% 计算密集型应用
内存使用率 > 75% < 40% 内存密集型应用
QPS (每秒请求数) > 1000/s < 400/s API 网关、Web 服务
连接数 > 5000 < 1000 数据库、消息队列
自定义业务指标 视业务而定 视业务而定 特定业务场景

5.2 扩容策略的"坑"与"解"

踩坑1:扩容反应太慢,流量洪峰已经把系统打挂了

某电商大促期间,设置 CPU > 80% 触发扩容,但监控采集有1分钟延迟,新实例启动需要3分钟。结果流量来得太快,扩容还没完成,服务器已经被打挂。

解决方案

  • 提前扩容:基于历史数据预测流量高峰,提前30分钟开始扩容
  • 多级阈值:设置 60% 预警(开始预热新实例)、70% 正式扩容、80% 紧急扩容
  • 快速扩容:使用容器化部署,新实例30秒内启动(相比虚拟机3-5分钟)

踩坑2:扩容太激进,成本爆炸

某创业公司设置了激进的自动扩容策略:CPU > 50% 就扩容。结果一个正常的业务波动就触发了扩容,服务器数量从5台膨胀到30台,月底云账单吓哭了 CTO。

解决方案

  • 设置扩容冷却时间:一次扩容后,至少等待5分钟才能再次扩容
  • 设置最大实例数:max = 当前实例数 × 2,防止无限膨胀
  • 区分突刺和趋势:只有连续3个周期都超过阈值才扩容,避免单点突刺触发

踩坑3:缩容太快,刚扩容的机器马上就缩了

某团队设置了 CPU < 30% 缩容。扩容后流量还在消化,CPU 短暂回落到 25%,触发了缩容。刚缩完 CPU 又飙到 80%,又触发扩容——系统在"扩容-缩容-扩容"中疯狂震荡。

解决方案

  • 缩容更保守:扩容阈值 70%,缩容阈值 25%,中间有足够的缓冲带
  • 缩容冷却时间更长:扩容后至少等待10分钟才能缩容
  • 渐进式缩容:一次只缩 1 台,观察后再决定要不要继续缩

6. 多区域部署:当"灾难"来临时

想象你的奶茶店生意火爆,但你只有一个店面。某天突如其来的暴雨把店淹了,你得停业整修两周。这两周里,所有顾客都跑去竞争对手那里了,等你重新开业,客源已经流失大半。

单点故障是系统架构中的"阿喀琉斯之踵"。多区域部署(Multi-Region Deployment)就是解决这个问题的方法:在不同地理位置部署多个数据中心,即使一个区域完全不可用,其他区域也能继续提供服务。

6.1 异地多活架构的核心概念

主备模式(Active-Standby

  • 只有一个区域对外提供服务(主),其他区域待命(备)
  • 备区实时同步数据,但不处理流量
  • 主区故障时,手动或自动切换到备区
  • 优点:架构简单,数据一致性好
  • 缺点:备区资源利用率低,切换时有中断

多活模式(Active-Active

  • 多个区域同时对外提供服务
  • 用户请求被路由到最近的区域
  • 区域之间实时同步数据
  • 优点:资源利用率高,故障影响小
  • 缺点:架构复杂,数据一致性挑战大

6.2 数据同步:多活架构的"阿喀琉斯之踵"

多活架构最大的挑战是数据一致性。当两个区域同时处理写入请求时,如何保证数据不会冲突?

场景示例

  • 北京区域:用户A给账户充值 100 元,余额从 200 变为 300
  • 上海区域:几乎同时,用户A消费 50 元,余额从 200 变为 150

如果两个区域分别执行后同步,最终余额应该是多少?300?150?还是其他值?

解决方案对比:

方案 原理 优点 缺点 适用场景
主从复制 只有一个主库可写,从库只读 实现简单,数据一致性好 主库单点,跨地域延迟大 读多写少,对一致性要求高
多主复制 多个主库可同时写,异步同步 写入性能高,就近写入 冲突解决复杂,可能丢数据 写入频繁,可接受短暂不一致
分布式事务 使用 2PC/3PC/TCC 等协议保证跨库事务 强一致性 性能开销大,复杂度高 金融交易等对一致性要求极高
CRDT(无冲突复制数据类型) 数学上保证无冲突的数据结构 自动合并,无需锁 数据类型受限,实现复杂 计数器、集合等特定场景

真实案例:全球电商平台的订单系统

某跨境电商在全球5个区域部署了数据中心。订单系统的架构设计如下:

  • 订单创建:使用"分区路由"策略,根据用户ID哈希确定主处理区域,该区域负责订单创建和初始状态变更,避免跨区域的写入冲突。

  • 库存扣减:使用分布式锁 + 乐观锁。库存数据以用户所在区域的副本为主,当跨区域访问时,先获取分布式锁,检查版本号,避免超卖。

  • 最终一致性:非关键数据(如推荐、统计)采用异步同步,允许秒级的延迟;关键数据(如支付状态)采用强同步,确保跨区一致性。

这套架构在实践中实现了 99.99% 的可用性,同时控制了跨区域同步的平均延迟在 100ms 以内。


7. 实战模板:从零搭建负载均衡架构

看完了理论,我们来动手实践。以下是一套可直接落地的架构方案。

7.1 中小型 Web 应用的推荐架构

场景:日活 10万 的电商平台,预算有限,团队规模 10人左右。

架构方案:

用户请求
    ↓
[DNS 轮询] 多地域就近访问
    ↓
[CDN] 静态资源缓存(图片、JS、CSS)
    ↓
[L7 负载均衡 - Nginx] SSL卸载、URL路由、限流
    ↓
[Web 服务器 - Node.js/Java] 业务逻辑处理
    ↓
[缓存层 - Redis Cluster] 会话、热点数据
    ↓
[数据库 - MySQL 主从] 读写分离

关键配置:

Nginx 负载均衡配置示例:

upstream backend {
    # 加权轮询,性能好的服务器权重更高
    server 10.0.1.10 weight=5;
    server 10.0.1.11 weight=3;
    server 10.0.1.12 weight=2 backup;  # backup 标记为备用

    keepalive 32;  # 长连接复用
}

server {
    listen 80;
    server_name api.example.com;

    # 健康检查
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }

    # 限流配置
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

    location /api/ {
        limit_req zone=api burst=20 nodelay;

        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 会话保持配置(基于IP哈希)
        # 注意:在 upstream 中配置 ip_hash; 代替加权轮询
    }

    # 静态资源缓存
    location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

7.2 系统架构演进建议

阶段一:起步期(日活 < 1万)

  • 单台服务器部署
  • Nginx 做反向代理 + 负载均衡
  • 重点关注:监控告警、日志收集

阶段二:成长期(日活 1万-10万)

  • 横向扩展:2-3 台 Web 服务器
  • 引入 Redis 做缓存和会话存储
  • MySQL 主从复制,读写分离
  • 引入 CDN 加速静态资源

阶段三:成熟期(日活 10万-100万)

  • 多地域部署,就近访问
  • 引入消息队列削峰填谷
  • 数据库分库分表
  • 自动化运维:CI/CD、自动扩缩容

8. 名词对照表

英文术语 中文对照 解释
Load Balancer 负载均衡器 将流量分发到多个后端服务器的设备或软件
L4 Load Balancing 四层负载均衡 基于传输层(TCP/UDP)的负载均衡
L7 Load Balancing 七层负载均衡 基于应用层(HTTP/HTTPS)的负载均衡
Health Check 健康检查 定期检查后端服务器健康状态的机制
Session Persistence 会话保持 确保同一用户的请求始终路由到同一台服务器
Sticky Session 粘性会话 另一种称呼,同 Session Persistence
Blue-Green Deployment 蓝绿部署 两套环境切换的零停机发布策略
Canary Release 金丝雀发布 小流量先行验证的灰度发布策略
Auto Scaling 自动扩缩容 根据负载自动增加或减少服务器数量
Horizontal Scaling 水平扩展 增加服务器数量来提升处理能力
Vertical Scaling 垂直扩展 提升单机配置(CPU、内存)来提升处理能力
Multi-Region 多区域 在多个地理区域部署服务
Active-Active 多活 多个区域同时对外提供服务
Active-Standby 主备 只有一个区域提供服务,其他待命
Data Replication 数据同步 跨区域的数据复制机制
RTO 恢复时间目标 系统故障后需要在多长时间内恢复
RPO 恢复点目标 系统故障后可以接受的数据丢失量

总结:负载均衡的核心思维

通过本文的学习,我们可以提炼出负载均衡设计的几个核心思维:

1. 分层思维

  • L4 处理"快递分拣"(快但简单)
  • L7 处理"内容检查"(慢但智能)
  • 根据场景选择合适的层次

2. 冗余思维

  • 单点故障是架构的敌人
  • 通过多实例、多区域部署提升可用性
  • 健康检查确保"坏节点"及时剔除

3. 渐进思维

  • 发布新版本不要"一刀切"
  • 蓝绿部署实现零停机
  • 金丝雀发布实现风险可控

4. 弹性思维

  • 系统应该像生命体一样"呼吸"
  • 忙时自动扩容,闲时自动缩容
  • 多区域部署实现就近服务和容灾

负载均衡不是简单的"流量分发",而是一套关于高可用、高性能、高弹性的系统工程思维。希望本文能帮助你在实际工作中做出更好的架构决策。