分篇三:分布式系统设计

一、CAP 定理

1. 定义

在一个分布式系统中,以下三个特性最多只能同时满足两个:

特性含义
C(Consistency,一致性)所有节点在同一时刻看到的数据一致
A(Availability,可用性)每个请求都能在合理时间内收到非错误响应
P(Partition tolerance,分区容错性)系统在网络分区发生时仍能继续运行

2. 为什么必须选 P

在真实分布式环境下,网络分区不可避免,因此 P 必须保留。实际选择只剩:

  • CP 系统:保证一致性,牺牲部分可用性。例:ZooKeeper、HBase
  • AP 系统:保证可用性,允许短暂不一致。例:Cassandra、DNS、DynamoDB

3. 案例题考法

通常不会直接问 CAP 定义,而是给出分布式场景让你分析:

  • 为什么该系统允许最终一致
  • 为什么该系统必须强一致
  • 某方案属于 CP 还是 AP

二、BASE 理论

1. 定义

BASE 是 CAP 中 AP 思路的落地指导,全称:

缩写含义说明
BA(Basically Available)基本可用允许部分功能降级或延迟,但核心可用
S(Soft State)软状态允许系统存在中间状态(如数据同步中)
E(Eventually Consistent)最终一致一段时间后所有副本数据趋于一致

2. BASE vs ACID

维度ACIDBASE
一致性模型强一致最终一致
关注点正确性可用性与吞吐
适用场景传统关系型数据库事务分布式系统
代表MySQL 事务NoSQL、消息队列

三、分布式事务

1. 为什么需要分布式事务

当业务操作跨越多个服务或多个数据库时,单机事务无法保证全局一致性。例如:下单扣库存 + 扣余额 + 创建订单,涉及三个服务。

2. 常见方案

2.1 两阶段提交(2PC)

原理:由一个协调者统一管理多个参与者的事务提交。

阶段一:准备阶段(Prepare/Vote)

  1. 协调者向所有参与者发送"准备提交"请求
  2. 各参与者执行事务操作(但不提交),写 undo/redo 日志
  3. 各参与者回复"同意"或"中止"

阶段二:提交阶段(Commit/Abort)

  • 如果所有参与者都同意:协调者发送"提交",所有参与者正式提交
  • 如果有任何一个参与者中止:协调者发送"回滚",所有参与者回滚

优点:保证强一致性

缺点:

  • 同步阻塞:参与者在等待协调者指令期间处于阻塞状态
  • 单点故障:协调者故障可能导致参与者永久阻塞
  • 数据不一致风险:网络异常时部分参与者可能提交、部分回滚
2.2 三阶段提交(3PC)

在 2PC 基础上增加了一个预提交(PreCommit)阶段,并引入了超时机制:

  1. CanCommit:协调者询问是否可以执行
  2. PreCommit:参与者预执行并锁定资源
  3. DoCommit:正式提交

改进点:减少阻塞、引入超时自动决策。
不足:实现复杂,仍无法完全避免不一致。

2.3 TCC(Try-Confirm-Cancel)

原理:将每个分布式操作拆分为三个阶段:

阶段含义说明
Try尝试预留资源(如冻结库存、冻结金额)
Confirm确认正式提交(扣除冻结的资源)
Cancel取消回滚(释放冻结的资源)

优点:

  • 无需数据库级锁,业务层面控制
  • 并发性能好

缺点:

  • 每个业务都要写 Try/Confirm/Cancel 三套逻辑,开发成本高
  • 需要保证 Confirm 和 Cancel 的幂等性

适用场景:高并发、对性能要求高的场景(如支付、转账)

2.4 Saga

原理:将一个长事务拆分为多个本地事务,每个本地事务有对应的补偿事务。正向执行时依次调用各本地事务;若某步失败,则逆序执行已完成步骤的补偿事务。

两种实现方式:

  • 编排式(Choreography):各服务通过事件驱动自行协调
  • 协调式(Orchestration):由一个中心协调器统一调度

优点:

  • 不需要分布式锁
  • 各步骤独立事务,性能好

缺点:

  • 只保证最终一致性
  • 补偿逻辑可能复杂
  • 编排式难以追踪全局状态

3. 分布式事务方案对比

方案一致性性能实现复杂度适用场景
2PC强一致差(阻塞)中传统数据库
3PC强一致一般高理论居多
TCC最终一致好高(三套逻辑)高并发业务
Saga最终一致好中长流程业务

四、分布式锁

1. 为什么需要分布式锁

当多个服务实例同时操作同一资源(如更新订单状态)时,需要互斥机制来保证同一时刻只有一个实例能执行关键操作。

2. 三种主流实现

2.1 基于数据库的分布式锁

实现方式:在数据库中创建一张锁表,通过插入记录抢锁,操作完成后删除记录释放锁。也可用SELECT ... FOR UPDATE行锁实现。

优点:

  • 实现简单,无需额外中间件
  • 数据持久化,便于审计

缺点:

  • 数据库成为单点,性能瓶颈
  • 若进程异常退出,锁记录可能永久存在(锁泄漏)
  • 高并发下锁争用严重
  • 无原生过期机制
2.2 基于 Redis 的分布式锁

实现方式:使用SET key value NX EX timeout命令:

  • NX:仅当 key 不存在时设置成功(互斥)
  • EX:设置过期时间(防死锁)
  • value:设为随机唯一值(释放时验证身份,防误删)

释放锁:用 Lua 脚本保证"检查 value + 删除 key"的原子性。

优点:

  • 性能高、延迟低
  • 支持自动过期

缺点:

  • 主从切换时可能丢锁(Master 挂掉,锁未同步到 Slave)
  • 需要处理续租问题(业务执行时间超过过期时间)
  • 实现需要注意原子性与幂等性

Redlock 算法(了解):为解决单节点 Redis 锁的可靠性问题,Redis 作者提出 Redlock:向 N 个独立 Redis 节点请求锁,获取 N/2+1 个以上才算成功。

2.3 基于 ZooKeeper 的分布式锁

实现方式:利用 ZooKeeper 的临时顺序节点:

  1. 每个客户端在指定路径下创建临时顺序节点
  2. 检查自己是否是序号最小的节点
  3. 如果是,获得锁;否则监听前一个节点的删除事件
  4. 前一个节点删除后,再检查自己是否最小

优点:

  • 客户端断开连接,临时节点自动删除(天然防死锁)
  • 顺序节点实现公平锁
  • ZooKeeper 集群本身高可用

缺点:

  • 性能不如 Redis(涉及 ZK 集群同步)
  • 需要维护 ZooKeeper 集群
  • 实现相对复杂
2.4 基于 Etcd 的分布式锁

实现方式:利用 Etcd 的租约(Lease)+ 前缀 + 事务机制。

优点:租约天然解决过期问题、强一致性(Raft 协议)。

缺点:相对小众,生态不如 ZK/Redis。

3. 分布式锁对比总结

维度数据库RedisZooKeeperEtcd
性能低高中中
可靠性中(单点)中(主从问题)高高
实现复杂度低中高高
防死锁需自行处理过期机制临时节点租约机制
公平性无无有(顺序节点)有

五、负载均衡

1. 定义

将请求分发到多个服务器实例,以提升系统吞吐量和可用性。

2. 常见算法

算法原理特点
轮询(Round Robin)依次分配给每台服务器简单、公平,不考虑服务器差异
加权轮询按权重分配,高性能机器分更多适应异构环境
随机随机选一台简单,大量请求下趋于均匀
最少连接分配给当前连接数最少的服务器适合长连接场景
IP 哈希对客户端 IP 取哈希决定分配保证同一客户端落到同一服务器
一致性哈希哈希环 + 虚拟节点节点增减时只影响相邻数据

3. 一致性哈希

原理:

  1. 将哈希值空间组织成一个虚拟的环(0 ~ 2^32-1)
  2. 将服务器节点映射到环上
  3. 将数据的 Key 也映射到环上,沿顺时针找到第一个服务器节点就是目标

虚拟节点:为避免数据倾斜,将每个物理节点映射为多个虚拟节点均匀分布在环上。

优点:增减节点时,只影响环上相邻区间的数据迁移,影响范围小。

适用场景:分布式缓存、分布式存储的数据分片。


六、服务治理

1. 服务注册与发现

组件说明
服务注册中心维护所有服务实例的地址信息(如 Nacos、Consul、Eureka、ZooKeeper)
服务注册服务启动时向注册中心登记自己的地址与元信息
服务发现调用方从注册中心获取目标服务的地址列表
健康检查注册中心定期探测服务实例是否存活

2. 限流

目的:保护系统不被突发流量击垮。

算法原理
固定窗口计数器在固定时间窗口内计数,超过阈值则拒绝
滑动窗口计数器窗口随时间滑动,统计更平滑
漏桶(Leaky Bucket)请求进入桶中,以固定速率流出
令牌桶(Token Bucket)以固定速率生成令牌,请求消耗令牌

3. 熔断

目的:当下游服务不可用时,快速失败,避免级联故障。

三种状态:

  • 关闭(Closed):正常调用,统计失败率
  • 打开(Open):达到阈值后直接返回错误,不再调用下游
  • 半开(Half-Open):一段时间后试探性放入少量请求,成功则关闭断路器

4. 降级

目的:系统压力过大时,主动放弃部分非核心功能,保证核心功能可用。

常见方式:

  • 返回兜底数据(如缓存中的旧数据)
  • 关闭非核心功能
  • 简化业务流程

5. 限流、熔断、降级的区别

维度限流熔断降级
保护对象保护自身保护自身(不被下游拖垮)保护核心功能
触发条件流量超阈值下游失败率过高系统资源不足
处理方式拒绝超出请求快速失败关闭非核心功能

七、微服务拆分原则

案例题如果涉及微服务设计,可能会问拆分原则:

  1. 单一职责原则:每个服务只做一件事
  2. 业务边界清晰:围绕业务能力拆分,而非技术层
  3. 高内聚低耦合:服务内部紧密相关,服务之间尽量独立
  4. 数据自治:每个服务拥有自己的数据库
  5. 可独立部署:服务升级不应要求其他服务同时升级
  6. 适当粒度:不要拆太细(增加运维复杂度),也不要太粗(退化为单体)

八、答题模板

分布式锁优缺点题

基于 [X] 的分布式锁:

  • 优点:1. … 2. …
  • 缺点:1. … 2. …
  • 适用场景:…

分布式事务对比题

按以下维度逐项对比:一致性级别、性能、实现复杂度、适用场景。

微服务概念题

微服务是一种架构风格,将单体应用拆分为一组小型服务,每个服务运行在独立进程中,通过轻量级通信机制协作,可独立部署。

优点:1. … 2. … 3. … 4. …

挑战:1. … 2. … 3. … 4. …