系统架构
负载均衡详解:原理、算法、Nginx 配置与架构实践
在网站或应用刚上线时,一台服务器通常就能处理用户请求。但随着访问量增加,单机可能逐渐出现响应变慢、资源占用过高,甚至服务中断等问题。 负载均衡通过将请求分配到多台服务器,使多个服务实例共同承担流量,从而提高系统的并发处理能力、可用性和扩展能力。 本文将介绍负载均衡的基本原理、常见算法、四层与七层负载均衡、Nginx 配置方法,以及引入负载均衡后需要处理的会话、文件存储、数据库和高可用问题。

1. 什么是负载均衡
负载均衡,英文为 Load Balancing,是一种将网络请求或业务流量分配到多台服务器上的技术。
它的核心作用,是避免所有请求集中到同一台服务器,让多个服务实例共同承担访问压力。
一个典型的负载均衡架构如下:
用户请求
↓
负载均衡器
├── 应用服务器 A
├── 应用服务器 B
└── 应用服务器 C
用户访问系统时,请求不会直接进入某一台应用服务器,而是先到达负载均衡器。
负载均衡器会根据预先设置的调度规则,从后端服务器中选择一台,将请求转发过去。
因此,可以把负载均衡器理解为系统入口处的“流量调度中心”。
2. 为什么需要负载均衡
负载均衡的作用并不仅仅是提高性能,它通常还承担高可用、扩容和发布管理等职责。
2.1 提高并发处理能力
单台服务器的 CPU、内存、网络连接数和线程数量都有上限。
当单机无法继续承受更多请求时,可以增加应用服务器,并通过负载均衡让多台服务器共同处理请求。
例如:
每秒 2,000 个请求
↓
负载均衡器
↓ ↓
服务器 A 服务器 B
约 1,000 约 1,000
这种通过增加服务器数量提升处理能力的方式,称为横向扩展。
2.2 避免单点故障
如果系统只有一台应用服务器,一旦服务器宕机,整个系统就会停止服务。
引入负载均衡后,当某台服务器发生故障时,负载均衡器可以停止向其转发请求,并将流量分配到其他正常节点。
用户请求
↓
负载均衡器
├── 服务器 A:故障
└── 服务器 B:正常
因此,负载均衡也是高可用架构的重要组成部分。
2.3 便于横向扩容
随着用户量增加,可以继续添加新的应用服务器。
扩容前:
负载均衡器
├── 服务器 A
└── 服务器 B扩容后:
负载均衡器
├── 服务器 A
├── 服务器 B
├── 服务器 C
└── 服务器 D
用户访问地址不需要改变,也不需要感知后端服务器数量的变化。
2.4 支持滚动更新
系统更新时,可以先将一台服务器从负载均衡中移除,完成更新并验证正常后,再重新加入集群。
随后继续更新下一台服务器。
这样可以在不中断整个系统服务的情况下完成版本升级,也就是常说的滚动发布。
3. 四层负载均衡和七层负载均衡
四层和七层是负载均衡中两个非常重要的概念。
它们的主要区别在于:负载均衡器能够识别请求中的哪些信息。
3.1 四层负载均衡
四层负载均衡工作在 OSI 网络模型的传输层,主要根据以下信息转发连接:
- 源 IP;
- 目标 IP;
- 源端口;
- 目标端口;
- TCP 或 UDP 协议。
例如:
目标 IP:203.0.113.10
目标端口:443
协议:TCP
四层负载均衡器通常不需要理解 HTTP 请求内容,只需要知道这是一个发往 443 端口的 TCP 连接,然后将连接转发给某一台后端服务器。
四层负载均衡常用于:
- TCP 服务;
- UDP 服务;
- 游戏服务器;
- 即时通信;
- 数据库代理;
- 高性能网络转发。
它的特点是:
- 转发性能较高;
- 协议适用范围广;
- 网络开销较低;
- 无法根据 URL、Cookie 等内容进行精细路由。
3.2 七层负载均衡
七层负载均衡工作在应用层,能够理解 HTTP、HTTPS 等应用协议。
它可以读取:
- 域名;
- URL 路径;
- HTTP 请求方法;
- Header;
- Cookie;
- 查询参数;
- 用户代理;
- 内容类型。
例如:
/api/user → 用户服务
/api/order → 订单服务
/static/ → 静态资源服务器
/upload/ → 文件服务
七层负载均衡可以根据请求内容进行更加灵活的转发。
Nginx 示例:
location /api/user/ {
proxy_pass http://user_service;
}
location /api/order/ {
proxy_pass http://order_service;
}
七层负载均衡常用于:
- 网站;
- Web API;
- 前后端分离系统;
- 微服务;
- API 网关;
- 灰度发布。
3.3 四层与七层的区别
| 对比项 | 四层负载均衡 | 七层负载均衡 |
|---|---|---|
| 工作层级 | TCP、UDP 传输层 | HTTP、HTTPS 应用层 |
| 是否理解 URL | 否 | 是 |
| 是否理解 Cookie | 否 | 是 |
| 路由能力 | 相对简单 | 更加灵活 |
| 转发性能 | 通常更高 | 相对略低 |
| 常见用途 | 游戏、数据库、TCP 服务 | 网站、接口、微服务 |
| 常见实现 | LVS、云四层负载均衡 | Nginx、HAProxy、网关 |
实际项目中,四层和七层负载均衡也可以组合使用:
用户
↓
四层云负载均衡
↓
七层 Nginx 集群
↓
应用服务集群
4. 常见负载均衡算法
负载均衡器需要决定将请求交给哪一台后端服务器,这个选择过程由负载均衡算法完成。
4.1 轮询
轮询是最简单、最常见的负载均衡算法。
负载均衡器按照服务器顺序依次分配请求:
第 1 个请求 → 服务器 A
第 2 个请求 → 服务器 B
第 3 个请求 → 服务器 C
第 4 个请求 → 服务器 A
优点:
- 实现简单;
- 分配相对均匀;
- 适合后端服务器配置相同的场景。
缺点:
- 不考虑服务器当前压力;
- 不考虑不同请求的处理时间;
- 不适合服务器性能差异较大的场景。
Nginx 默认使用轮询:
upstream backend {
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
4.2 加权轮询
加权轮询是在普通轮询基础上,为不同服务器设置不同权重。
性能更强的服务器可以设置更高权重,从而接收更多请求。
例如:
服务器 A:8 核 CPU,权重为 2
服务器 B:4 核 CPU,权重为 1
最终分配效果大致为:
服务器 A 接收约 2/3 的请求
服务器 B 接收约 1/3 的请求
Nginx 配置:
upstream backend {
server 10.0.0.11:8080 weight=2;
server 10.0.0.12:8080 weight=1;
}
加权轮询适合后端服务器配置不完全一致的情况。
4.3 最少连接数
最少连接算法会优先将新请求发送给当前连接数最少的服务器。
例如:
服务器 A:100 个连接
服务器 B:30 个连接
服务器 C:70 个连接
新的请求会优先分配给服务器 B。
这种算法适合:
- 请求处理时间差异较大;
- WebSocket 长连接;
- 文件下载;
- 视频服务;
- 实时通信。
Nginx 配置:
upstream backend {
least_conn;
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
需要注意的是,连接数少并不一定意味着服务器 CPU 或内存压力最低,但它通常比普通轮询更适合长连接场景。
4.4 IP Hash
IP Hash 会根据客户端 IP 计算哈希值,让同一个客户端尽量访问同一台服务器。
用户甲 → 服务器 A
用户乙 → 服务器 B
用户甲再次访问 → 仍然进入服务器 A
Nginx 配置:
upstream backend {
ip_hash;
server 10.0.0.11:8080;
server 10.0.0.12:8080;
}
优点:
- 可以在一定程度上实现会话保持;
- 配置简单。
缺点:
- 多个用户可能经过同一个运营商 NAT 或代理出口;
- 流量分配可能不均匀;
- 扩容和缩容后,映射关系可能变化;
- 服务器故障后,会话仍可能丢失。
因此,IP Hash 不应该作为登录状态设计的主要方案。
4.5 一致性哈希
普通哈希算法在增加或删除服务器时,可能导致大量请求重新映射。
一致性哈希可以尽量减少节点变化造成的映射范围,从而降低缓存失效和数据迁移带来的影响。
一致性哈希常用于:
- 分布式缓存;
- Redis 集群;
- CDN;
- 分片存储;
- 长连接服务。
例如,原来有 A、B、C 三台服务器,增加服务器 D 后,只需要重新分配部分请求,而不是重新计算全部映射。
4.6 最短响应时间
最短响应时间算法会综合考虑:
- 当前连接数;
- 网络延迟;
- 历史响应时间;
- 节点健康状态。
然后将请求优先分配给响应速度更快的服务器。
这种方式比普通轮询更加智能,但实现也更复杂。是否支持该算法,取决于具体负载均衡产品及版本。
4.7 随机算法
随机算法会从可用后端服务器中随机选择一台。
当服务器数量较多、请求量较大时,随机算法也能够获得较为均匀的分配结果。
它的实现简单,但无法准确反映服务器实时负载。
5. 负载均衡的常见实现方式
5.1 硬件负载均衡
硬件负载均衡使用专门的网络设备处理流量。
通常应用于:
- 金融机构;
- 电信系统;
- 大型政务平台;
- 大型数据中心;
- 高并发核心业务。
优点:
- 性能高;
- 稳定性强;
- 功能完整;
- 通常具有专业技术支持。
缺点:
- 采购成本高;
- 部署复杂;
- 扩容成本较高;
- 容易产生厂商依赖。
普通中小型系统一般没有必要使用专用硬件负载均衡设备。
5.2 软件负载均衡
软件负载均衡是在普通服务器上安装软件实现流量转发。
常见软件包括:
- Nginx;
- HAProxy;
- LVS;
- Traefik;
- Envoy;
- Apache HTTP Server。
优点:
- 成本较低;
- 灵活性高;
- 易于部署;
- 适合大多数互联网系统。
缺点:
- 需要自行维护;
- 高可用需要额外设计;
- 性能受服务器配置影响;
- 软件负载均衡器本身可能成为单点。
5.3 云负载均衡
云负载均衡是由云平台提供的托管式负载均衡服务。
典型架构如下:
互联网用户
↓
云负载均衡
↓
云服务器 A、B、C
云负载均衡通常提供:
- 公网访问入口;
- 流量分发;
- 健康检查;
- HTTPS 证书管理;
- 访问日志;
- 监控告警;
- 多可用区容灾;
- 与弹性伸缩配合。
它的主要优点是维护成本较低,用户不需要自行搭建负载均衡高可用集群。
6. Nginx 负载均衡配置
下面是一个基本的 Nginx 负载均衡配置。
upstream application_cluster {
least_conn;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://application_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
访问流程如下:
用户访问 example.com
↓
Nginx
↓
从 101、102、103 中选择一台服务器
↓
应用服务器处理请求
↓
Nginx 将响应返回给用户
6.1 配置节点失败判断
upstream application_cluster {
server 192.168.1.101:8080 max_fails=3 fail_timeout=30s;
server 192.168.1.102:8080 max_fails=3 fail_timeout=30s;
}
这里的含义大致是:
- 在
fail_timeout时间范围内; - 某个节点的请求失败次数达到
max_fails; - 该节点会在一段时间内被视为不可用;
- 后续再重新尝试访问。
需要注意,Nginx 开源版的这类机制主要属于被动健康检查。
它不是定期主动调用 /health 接口,而是根据真实请求中出现的连接失败、超时等情况判断节点是否异常。
此外,请求失败后的自动重试需要谨慎使用。
对于查询类请求,重试一般问题较小;对于创建订单、支付、提交表单等写操作,如果接口没有幂等设计,重试可能导致重复执行。
6.2 配置备用服务器
upstream application_cluster {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080 backup;
}
在前两台服务器正常时,备用服务器不会接收请求。
当前面的服务器都不可用时,备用服务器才会开始处理流量。
7. 健康检查与故障转移
负载均衡器不能只负责分配请求,还必须知道后端服务器是否正常。
否则可能出现以下情况:
服务器 A 已经宕机
↓
负载均衡器仍向服务器 A 转发请求
↓
用户持续收到错误响应
健康检查的作用,就是识别异常节点,并将其从可用服务器列表中临时移除。
7.1 TCP 健康检查
TCP 健康检查会尝试与目标服务器的指定端口建立连接。
例如:
10.0.0.11:8080
如果端口可以正常建立连接,说明该服务在网络和进程层面基本可达。
优点:
- 实现简单;
- 检查开销较小;
- 适合非 HTTP 服务。
缺点:
- 端口能够连接,不代表业务功能正常;
- 应用可能已经卡死,但端口仍在监听;
- 无法检查数据库或其他依赖是否可用。
7.2 HTTP 健康检查
HTTP 健康检查会定期请求一个专用接口,例如:
GET /health
正常返回:
{
"status": "UP"
}
负载均衡器可以根据响应状态判断节点是否健康:
- HTTP 200:正常;
- HTTP 500:异常;
- 请求超时:异常;
- 无法建立连接:异常。
相比 TCP 检查,HTTP 检查更接近真实业务状态。
7.3 存活检查与就绪检查
健康检查不宜把所有依赖状态简单绑定在一起。
例如:
{
"application": "UP",
"database": "UP",
"redis": "UP",
"storage": "UP"
}
如果数据库出现短暂抖动,所有应用节点都可能同时返回不健康,负载均衡器随后摘除全部服务器,反而扩大故障范围。
因此,实际系统通常会区分:
- 存活检查:应用进程是否仍在正常运行;
- 就绪检查:应用当前是否可以接收流量;
- 依赖检查:数据库、Redis、对象存储等组件是否正常。
在 Kubernetes 中,对应的检查包括:
- Liveness Probe;
- Readiness Probe;
- Startup Probe。
7.4 节点摘除与恢复
典型规则可能是:
连续 3 次检查失败 → 摘除节点
连续 2 次检查成功 → 恢复节点
设置连续失败和连续成功次数,可以避免偶发网络抖动导致节点频繁上线、下线。
8. 引入负载均衡后需要解决的问题
增加负载均衡和应用服务器并不代表系统已经自动具备完整的集群能力。
应用还需要处理会话、文件、缓存、任务和数据库等问题。
8.1 会话一致性问题
负载均衡后,同一个用户的不同请求可能进入不同服务器。
例如:
用户登录请求 → 服务器 A
用户查询请求 → 服务器 B
如果登录状态只保存在服务器 A 的内存中,那么服务器 B 就无法识别用户已经登录。
这就是会话一致性问题。
方案一:会话保持
让同一用户尽量持续访问同一台服务器。
常见方式包括:
- IP Hash;
- Cookie 粘性会话;
- Session Affinity。
优点是改造简单。
但它也存在明显缺点:
- 服务器故障后会话可能丢失;
- 流量分配可能不均匀;
- 不利于弹性扩容;
- 用户与服务器形成绑定。
方案二:共享 Session
将 Session 保存在 Redis 等集中式存储中。
服务器 A ─┐
服务器 B ─┼── Redis Session
服务器 C ─┘
无论请求落到哪一台服务器,都可以从 Redis 读取登录状态。
这是传统 Web 系统中比较常见的解决方案。
方案三:无状态 Token
用户登录成功后,由服务器签发 Token,例如 JWT。
客户端后续请求携带:
Authorization: Bearer <token>
任何持有验证密钥的服务器都可以验证 Token,因此登录状态不再绑定某一台应用服务器。
这种方式适合:
- 前后端分离系统;
- 移动端应用;
- 微服务系统;
- 多服务器部署。
但无状态 Token 并不代表系统完全没有服务端状态。
以下功能仍可能需要 Redis 或数据库支持:
- Token 注销;
- 强制下线;
- Token 黑名单;
- 权限即时变更;
- 刷新令牌管理;
- 多设备登录控制。
总体原则是:
应用服务应尽量设计为无状态,业务状态存放在数据库、Redis或共享存储中。
8.2 文件上传问题
假设用户上传了一张图片,请求被分配给服务器 A。
如果图片只存储在服务器 A 的本地磁盘中:
用户上传 → 服务器 A 本地磁盘
用户查看 → 请求被转发到服务器 B
服务器 B 找不到该文件,就会出现访问失败。
因此,在负载均衡环境下,不应将业务文件只保存在某台应用服务器的本地磁盘中。
常见解决方案包括:
- 对象存储;
- NAS;
- 共享文件系统;
- 分布式文件系统;
- 独立文件服务器。
推荐结构:
应用服务器 A ─┐
应用服务器 B ─┼── 对象存储或共享存储
应用服务器 C ─┘
应用服务器本地磁盘通常只适合保存:
- 临时文件;
- 本地缓存;
- 运行日志;
- 可以重新生成的数据。
8.3 本地缓存一致性
如果每台应用服务器都使用自己的本地缓存,可能出现数据不一致。
例如:
服务器 A 已更新缓存
服务器 B 仍保存旧数据
用户访问不同服务器时,可能看到不同结果。
常见解决方法包括:
- 使用 Redis 等集中式缓存;
- 使用消息通知使本地缓存失效;
- 给缓存设置合理过期时间;
- 避免将关键业务状态只放在本地缓存中。
8.4 定时任务重复执行
假设系统有三台应用服务器,并且每台服务器都运行相同的定时任务。
服务器 A 执行一次
服务器 B 执行一次
服务器 C 执行一次
原本只需要执行一次的任务,可能被重复执行三次。
常见解决方案包括:
- 使用独立任务调度平台;
- 使用分布式锁;
- 指定单节点执行;
- 将任务处理设计为幂等;
- 使用消息队列分发任务。
8.5 请求幂等问题
负载均衡器、网关或客户端在请求失败后,可能重新发起请求。
对于查询操作,重复请求通常没有明显影响。
但对于以下操作,重复执行可能造成严重问题:
- 创建订单;
- 支付扣款;
- 数据提交;
- 发放优惠券;
- 库存扣减。
因此,重要写操作应使用唯一业务请求编号,并保证相同请求只能成功处理一次。
8.6 数据库瓶颈
应用服务器可以比较容易地增加多台,但数据库不能简单照搬这种扩容方式。
应用服务器 A
应用服务器 B
应用服务器 C
↓
MySQL
即使应用层进行了负载均衡,所有请求仍然可能访问同一个数据库,数据库会成为新的瓶颈。
常见解决方案包括:
主节点与只读副本
主数据库
/ \
只读副本 A 只读副本 B
通常:
- 写操作进入主数据库;
- 查询操作分配到只读副本。
这种方式称为读写分离。
需要注意,数据库复制可能存在延迟。刚写入主库的数据,不一定能够立即从只读副本中查询到。
数据库代理
应用服务器
↓
数据库代理
↓ ↓
主库 只读副本
数据库代理可以根据请求类型,将读写操作分配到不同数据库节点。
分库分表
当单个数据库的数据量、写入量或查询压力过大时,可以按用户、机构、区域或时间等维度拆分数据。
但分库分表会带来较高复杂度,包括:
- 跨库查询;
- 分布式事务;
- 全局唯一 ID;
- 数据迁移;
- 分页与排序;
- 聚合统计。
因此,不能因为应用服务器使用了负载均衡,就过早进行分库分表。
9. 负载均衡器本身也可能成为单点
假设系统架构如下:
用户
↓
单台 Nginx
↓
多台应用服务器
虽然应用服务器有多台,但 Nginx 只有一台。
一旦 Nginx 宕机,用户仍然无法访问整个系统。
这就是负载均衡器自身的单点故障。
9.1 使用云负载均衡
用户
↓
云负载均衡
↓
应用服务器集群
云负载均衡通常由云平台负责底层高可用。
对于中小型系统,这是维护成本较低、实现相对简单的方案。
9.2 双 Nginx 加 Keepalived
本地机房或自建环境可以采用双 Nginx 加 Keepalived。
虚拟 IP
↓
┌────────────────┐
↓ ↓
主 Nginx 备 Nginx
└──────┬─────────┘
↓
应用服务器集群
正常情况下,虚拟 IP 由主 Nginx 提供服务。
当主 Nginx 故障后,Keepalived 将虚拟 IP 切换到备用 Nginx,用户仍然访问原来的地址。
需要注意,在部分云环境中,传统虚拟 IP 漂移可能受到网络架构限制,不能直接照搬本地机房方案。
10. 负载均衡与反向代理的区别
负载均衡和反向代理经常同时出现,但它们强调的重点不同。
10.1 反向代理
反向代理代表后端服务器接收客户端请求。
客户端只知道代理服务器的地址,并不知道真正的后端服务器地址。
反向代理可以实现:
- 隐藏后端服务器;
- HTTPS 终止;
- 请求转发;
- 静态资源处理;
- 缓存;
- 压缩;
- 限流;
- 鉴权;
- 日志记录。
10.2 负载均衡
负载均衡强调的是:
将请求分配给多个后端服务实例。
一台 Nginx 可以同时承担:
- 反向代理;
- 七层负载均衡;
- HTTPS 入口;
- 静态资源服务器;
- 简单 API 网关。
因此,反向代理和负载均衡并不冲突。
当后端只有一台服务器时,Nginx 主要承担反向代理作用;当后端有多台服务器时,它还可以承担负载均衡作用。
11. 什么时候需要负载均衡
是否需要负载均衡,不能只看用户数量,还要结合性能、可用性和运维要求判断。
11.1 性能方面
当系统出现以下情况时,可以考虑增加应用服务器并引入负载均衡:
- CPU 长时间维持较高水平;
- 内存长期接近容量上限;
- 高峰期接口响应明显变慢;
- 单机连接数接近瓶颈;
- 单机吞吐量不足;
- 高峰期频繁出现超时;
- 垃圾回收过于频繁;
- 应用进程经常被打满。
有些项目会将 CPU 长期超过 70% 作为预警参考,但 70% 并不是固定标准。
是否需要扩容,还应结合以下指标判断:
- 请求量;
- 响应时间;
- 错误率;
- GC 情况;
- 数据库压力;
- 带宽占用;
- 业务增长趋势。
而且必须先确认瓶颈确实位于应用服务器,而不是慢 SQL、网络带宽或外部接口。
11.2 可用性方面
即使业务访问量不大,如果系统有以下要求,也可能需要负载均衡:
- 不能因单台服务器故障而停止服务;
- 需要全年持续运行;
- 有明确的 SLA;
- 系统升级时不能中断;
- 需要跨可用区容灾;
- 用于关键医疗、政务或生产业务。
此时引入负载均衡的主要目的不是提高并发,而是提高可用性。
11.3 发布和运维方面
当系统需要以下能力时,负载均衡也具有较高价值:
- 滚动发布;
- 灰度发布;
- 无停机升级;
- 快速回滚;
- 多版本并存;
- 故障节点自动摘除。
12. 常见架构演进与选型建议
负载均衡架构应根据业务规模逐步演进,而不是在项目初期一次性搭建复杂集群。
12.1 小型系统:单机部署
用户
↓
单台服务器
├── Nginx
├── 应用程序
└── MySQL
适合:
- 开发测试;
- 小型网站;
- 项目早期;
- 低并发业务;
- 可以接受短时间维护中断的系统。
这一阶段通常不需要负载均衡。
更应该优先做好:
- 数据库备份;
- 日志记录;
- 安全防护;
- 接口限流;
- 监控告警;
- 数据恢复演练。
12.2 应用与数据库分离
用户
↓
应用服务器
↓
数据库服务器
当应用程序和数据库相互争抢 CPU、内存或磁盘资源时,可以先将应用和数据库分离。
这通常比直接搭建复杂集群更有效。
12.3 中小型生产系统
用户
↓
云负载均衡
↓
应用服务器 A、B
↓
Redis、MySQL、对象存储
这种架构相对简单,同时可以提供:
- 基本应用高可用;
- 横向扩容能力;
- Session 共享;
- 文件集中存储;
- 滚动发布能力。
这是许多中小型生产系统比较实用的方案。
12.4 本地机房系统
虚拟 IP
↓
双 Nginx + Keepalived
↓
应用服务器集群
↓
数据库与共享存储
除了负载均衡,还需要评估:
- 交换机是否单点;
- 网络出口是否单点;
- 电源是否单点;
- 存储是否单点;
- 数据库是否单点;
- 备份是否可恢复。
不能只增加两台 Nginx,就认为整个系统已经具备高可用能力。
12.5 微服务系统
公网负载均衡
↓
API 网关
↓
服务注册与发现
↓
多个微服务实例
微服务系统中,负载均衡可能存在于多个层级:
- 外部用户到 API 网关;
- API 网关到微服务;
- 微服务之间调用;
- 服务网格内部流量调度。
12.6 多地域或超大型系统
DNS 或全局流量调度
↓
多个地域或数据中心
↓
区域负载均衡
↓
网关集群
↓
应用服务集群
这种架构适合:
- 用户分布在多个地区;
- 需要异地容灾;
- 访问量非常大;
- 对连续服务能力要求较高的系统。
13. 负载均衡设计的核心原则
负载均衡设计可以归纳为以下几点。
1. 应用尽量无状态
Session、文件和关键业务状态不要只保存在单台应用服务器本地。
2. 必须配置健康检查
否则负载均衡器无法及时发现和排除异常节点。
3. 负载均衡器本身也要高可用
不能只解决应用服务器单点,却将新的单点转移到负载均衡器。
4. 数据库和存储需要单独评估
应用服务器集群并不代表数据库、文件存储和缓存已经高可用。
5. 重要写操作必须具备幂等性
防止客户端重试、网关重试或网络抖动导致重复下单、重复扣款或重复写入。
6. 先定位瓶颈,再决定是否扩容
负载均衡不能解决所有性能问题。
以下问题即使增加应用服务器也未必有效:
- 慢 SQL;
- 数据库锁竞争;
- 第三方接口响应慢;
- 网络带宽不足;
- 程序死锁;
- 不合理的缓存设计;
- 单线程串行任务。
7. 架构复杂度要与业务规模匹配
小型系统过早集群化,通常会增加:
- 服务器成本;
- 运维成本;
- 故障点数量;
- 部署复杂度;
- 问题排查难度。
负载均衡应该在确有性能、高可用或发布管理需求时引入,而不是作为所有系统的默认配置。