水平扩展与负载均衡
扩展性设计的核心一句话:把状态外置,让任何实例都能服务任何请求。面试主线:无状态设计、扩展方式、LB 选型。
无状态设计
水平扩展的前提是应用无状态:
- Session 外置:登录态放 Redis 或 JWT(无状态令牌),不放进程内存
- 本地缓存只放容忍丢失的数据(见缓存设计篇),业务状态放共享存储
- 实例可随时增减,请求打到任意实例结果一致
有状态的痛:Session 在实例 A,请求被 LB 分到 B 就丢失。解法要么状态外置,要么会话粘滞(sticky session,扩展受限)。
垂直 vs 水平
| 维度 | 垂直扩展 | 水平扩展 |
|---|---|---|
| 做法 | 换更大的机器 | 加更多机器 |
| 上限 | 单机天花板 | 理论无限 |
| 成本 | 非线性增长(大机器贵) | 线性(普通机器堆量) |
| 复杂度 | 无 | 有(LB、状态外置、数据分片) |
| 适用 | 起步阶段、状态难拆的组件 | 稳定后的主流路径 |
弹性伸缩:水平扩展的自动化。按指标(CPU、QPS、队列长度)自动加/减实例。注意:伸缩有滞后(启动要时间),提前规划阈值和预热。
四层 vs 七层负载均衡
L4 转发, L7 决策
| 维度 | L4(传输层) | L7(应用层) |
|---|---|---|
| 工作层 | IP/端口 | HTTP 内容(URL/Header/Cookie) |
| 性能 | 高(不解析内容) | 有解析开销 |
| 能力 | 转发 | 路由、重写、限流、鉴权、压缩 |
| 场景 | 高吞吐流量入口 | 精细化路由控制 |
生产组合:L4 挡最外层大流量,L7 做精细路由(Nginx 是 L7 主力,LVS 是 L4 主力)。选型要点:纯转发高吞吐用 L4,需要内容路由用 L7。
负载均衡算法
| 算法 | 机制 | 适用 |
|---|---|---|
| 轮询 | 逐个分发 | 无状态、等权重 |
| 加权轮询 | 按权重 | 机器性能不均 |
| 最少连接 | 分给连接最少的 | 长连接场景 |
| 一致性哈希 | 按 key 哈希到固定节点 | 有状态场景(缓存、会话) |
一致性哈希要点:节点增减只影响少量 key(环上相邻),比普通取模(全部重映射)适合缓存分片。代价:key 分布可能不均,配虚拟节点缓解。
面试追问
- 水平扩展的前提? 无状态:Session 外置(Redis/JWT)、业务状态进共享存储。有状态组件是扩展的天花板
- L4 和 L7 的区别? L4 传输层转发(快、无内容感知),L7 应用层路由(功能全、有开销)。生产双层组合
- 一致性哈希解决什么? 节点增减只影响少量 key。缓存分片用,普通取模增减节点全量重映射
- 会话粘滞有什么问题? 请求被钉在固定实例,实例挂了会话丢,扩缩容困难。状态外置是正解
- 弹性伸缩的难点? 滞后性:实例启动要时间,突发流量来不及扩。提前预热、按队列长度等前瞻指标触发