一、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
| 维度 | ACID | BASE |
|---|---|---|
| 一致性模型 | 强一致 | 最终一致 |
| 关注点 | 正确性 | 可用性与吞吐 |
| 适用场景 | 传统关系型数据库事务 | 分布式系统 |
| 代表 | MySQL 事务 | NoSQL、消息队列 |
三、分布式事务
1. 为什么需要分布式事务
当业务操作跨越多个服务或多个数据库时,单机事务无法保证全局一致性。例如:下单扣库存 + 扣余额 + 创建订单,涉及三个服务。
2. 常见方案
2.1 两阶段提交(2PC)
原理: 由一个协调者 统一管理多个参与者的事务提交。
阶段一:准备阶段(Prepare/Vote)
- 协调者向所有参与者发送"准备提交"请求
- 各参与者执行事务操作(但不提交),写 undo/redo 日志
- 各参与者回复"同意"或"中止"
阶段二:提交阶段(Commit/Abort)
- 如果所有参与者都同意:协调者发送"提交",所有参与者正式提交
- 如果有任何一个参与者中止:协调者发送"回滚",所有参与者回滚
优点: 保证强一致性
缺点:
- 同步阻塞:参与者在等待协调者指令期间处于阻塞状态
- 单点故障:协调者故障可能导致参与者永久阻塞
- 数据不一致风险:网络异常时部分参与者可能提交、部分回滚
2.2 三阶段提交(3PC)
在 2PC 基础上增加了一个预提交(PreCommit)阶段,并引入了超时机制:
- CanCommit:协调者询问是否可以执行
- PreCommit:参与者预执行并锁定资源
- 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 的临时顺序节点:
- 每个客户端在指定路径下创建临时顺序节点
- 检查自己是否是序号最小的节点
- 如果是,获得锁;否则监听前一个节点的删除事件
- 前一个节点删除后,再检查自己是否最小
优点:
- 客户端断开连接,临时节点自动删除(天然防死锁)
- 顺序节点实现公平锁
- ZooKeeper 集群本身高可用
缺点:
- 性能不如 Redis(涉及 ZK 集群同步)
- 需要维护 ZooKeeper 集群
- 实现相对复杂
2.4 基于 Etcd 的分布式锁
实现方式: 利用 Etcd 的租约(Lease)+ 前缀 + 事务机制。
优点: 租约天然解决过期问题、强一致性(Raft 协议)。
缺点: 相对小众,生态不如 ZK/Redis。
3. 分布式锁对比总结
| 维度 | 数据库 | Redis | ZooKeeper | Etcd |
|---|---|---|---|---|
| 性能 | 低 | 高 | 中 | 中 |
| 可靠性 | 中(单点) | 中(主从问题) | 高 | 高 |
| 实现复杂度 | 低 | 中 | 高 | 高 |
| 防死锁 | 需自行处理 | 过期机制 | 临时节点 | 租约机制 |
| 公平性 | 无 | 无 | 有(顺序节点) | 有 |
五、负载均衡
1. 定义
将请求分发到多个服务器实例,以提升系统吞吐量和可用性。
2. 常见算法
| 算法 | 原理 | 特点 |
|---|---|---|
| 轮询(Round Robin) | 依次分配给每台服务器 | 简单、公平,不考虑服务器差异 |
| 加权轮询 | 按权重分配,高性能机器分更多 | 适应异构环境 |
| 随机 | 随机选一台 | 简单,大量请求下趋于均匀 |
| 最少连接 | 分配给当前连接数最少的服务器 | 适合长连接场景 |
| IP 哈希 | 对客户端 IP 取哈希决定分配 | 保证同一客户端落到同一服务器 |
| 一致性哈希 | 哈希环 + 虚拟节点 | 节点增减时只影响相邻数据 |
3. 一致性哈希
原理:
- 将哈希值空间组织成一个虚拟的环(0 ~ 2^32-1)
- 将服务器节点映射到环上
- 将数据的 Key 也映射到环上,沿顺时针找到第一个服务器节点就是目标
虚拟节点: 为避免数据倾斜,将每个物理节点映射为多个虚拟节点均匀分布在环上。
优点: 增减节点时,只影响环上相邻区间的数据迁移,影响范围小。
适用场景: 分布式缓存、分布式存储的数据分片。
六、服务治理
1. 服务注册与发现
| 组件 | 说明 |
|---|---|
| 服务注册中心 | 维护所有服务实例的地址信息(如 Nacos、Consul、Eureka、ZooKeeper) |
| 服务注册 | 服务启动时向注册中心登记自己的地址与元信息 |
| 服务发现 | 调用方从注册中心获取目标服务的地址列表 |
| 健康检查 | 注册中心定期探测服务实例是否存活 |
2. 限流
目的: 保护系统不被突发流量击垮。
| 算法 | 原理 |
|---|---|
| 固定窗口计数器 | 在固定时间窗口内计数,超过阈值则拒绝 |
| 滑动窗口计数器 | 窗口随时间滑动,统计更平滑 |
| 漏桶(Leaky Bucket) | 请求进入桶中,以固定速率流出 |
| 令牌桶(Token Bucket) | 以固定速率生成令牌,请求消耗令牌 |
3. 熔断
目的: 当下游服务不可用时,快速失败,避免级联故障。
三种状态:
- 关闭(Closed):正常调用,统计失败率
- 打开(Open):达到阈值后直接返回错误,不再调用下游
- 半开(Half-Open):一段时间后试探性放入少量请求,成功则关闭断路器
4. 降级
目的: 系统压力过大时,主动放弃部分非核心功能,保证核心功能可用。
常见方式:
- 返回兜底数据(如缓存中的旧数据)
- 关闭非核心功能
- 简化业务流程
5. 限流、熔断、降级的区别
| 维度 | 限流 | 熔断 | 降级 |
|---|---|---|---|
| 保护对象 | 保护自身 | 保护自身(不被下游拖垮) | 保护核心功能 |
| 触发条件 | 流量超阈值 | 下游失败率过高 | 系统资源不足 |
| 处理方式 | 拒绝超出请求 | 快速失败 | 关闭非核心功能 |
七、微服务拆分原则
案例题如果涉及微服务设计,可能会问拆分原则:
- 单一职责原则:每个服务只做一件事
- 业务边界清晰:围绕业务能力拆分,而非技术层
- 高内聚低耦合:服务内部紧密相关,服务之间尽量独立
- 数据自治:每个服务拥有自己的数据库
- 可独立部署:服务升级不应要求其他服务同时升级
- 适当粒度:不要拆太细(增加运维复杂度),也不要太粗(退化为单体)
八、答题模板
分布式锁优缺点题
基于 [X] 的分布式锁:
- 优点:1. ... 2. ...
- 缺点:1. ... 2. ...
- 适用场景:...
分布式事务对比题
按以下维度逐项对比:一致性级别、性能、实现复杂度、适用场景。
微服务概念题
微服务是一种架构风格,将单体应用拆分为一组小型服务,每个服务运行在独立进程中,通过轻量级通信机制协作,可独立部署。
优点: 1. ... 2. ... 3. ... 4. ...
挑战: 1. ... 2. ... 3. ... 4. ...