🌐 第五章 · 分布式系统
分布式系统架构
本章涵盖CAP定理、分布式一致性协议、分布式事务、缓存架构和消息队列等核心考点,占综合知识考试7%-13%的分值。分布式系统是近年来的高频考点,需重点掌握。
7%-13%考试分值占比
8知识模块
★★★★★重要程度
15章节测验题
CAP定理与BASE理论
核心考点⚖️CAP定理详解
CAP定理由Eric Brewer于2000年提出,是分布式系统设计的理论基础。它指出一个分布式系统不可能同时满足以下三个特性:
| 特性 | 英文 | 含义 | 说明 |
|---|---|---|---|
| C 一致性 | Consistency | 所有节点在同一时间看到的数据是相同的 | 每次读操作都能读到最新的写操作结果。等同于线性一致性 |
| A 可用性 | Availability | 每个请求都能在合理时间内收到非错误的响应 | 不保证数据是最新的,但保证每次请求都有响应 |
| P 分区容错性 | Partition Tolerance | 网络分区时系统仍能继续工作 | 网络分区是必然存在的,分布式系统必须具备分区容错能力 |
核心结论(必考):在分布式系统中,P(分区容错性)是必然存在的,因为网络不可靠。因此系统只能在C(一致性)和A(可用性)之间做选择,不可能三者兼得。
CAP定理示意 — 三者最多取其二
C
一致性
一致性
A
可用性
可用性
P
分区容错
分区容错
分布式系统中 P 必须满足,实际在 C 与 A 间权衡
🔄CP系统 vs AP系统
| 对比维度 | CP系统(一致性优先) | AP系统(可用性优先) |
|---|---|---|
| 选择 | 保证一致性 + 分区容错性 | 保证可用性 + 分区容错性 |
| 行为 | 网络分区时拒绝部分请求以保证数据一致 | 网络分区时继续响应,数据可能不一致 |
| 典型系统 | Zookeeper、HBase、etcd | Cassandra、Eureka、Dynamo |
| 适用场景 | 金融交易、选举系统 | 社交网络、内容分发 |
| 一致性 | 强一致性 | 最终一致性 |
📋BASE理论
BA(Basically Available)基本可用:分布式系统在出现故障时,允许损失部分可用性,但保证核心功能可用。例如:电商大促时部分非核心服务降级
S(Soft State)软状态:允许系统中存在中间状态,该状态不影响系统整体可用性。例如:数据同步过程中的延迟
E(Eventually Consistent)最终一致性:经过一段时间后,系统中的所有数据副本最终会达到一致状态。不要求实时一致
CAP与BASE的关系:BASE理论是对CAP中AP方案的延伸,是大规模分布式系统的工程实践总结。BASE用"基本可用+软状态+最终一致性"替代了传统的ACID强一致性要求。
分布式一致性协议
高频🏛️Paxos算法
角色:Proposer(提议者,提出提案)、Acceptor(接受者,投票决定)、Learner(学习者,学习被选定的提案)
核心思想:通过多数派(Quorum)决议来保证一致性。任意两个多数派必有交集
两阶段:Prepare阶段(Proposer获取提议权)→ Accept阶段(Proposer提交提案并获多数接受)
问题:活锁问题(多个Proposer冲突),工程实现复杂
🌲Raft算法
Raft是Paxos的工程化实现,更易理解和实现。它将一致性问题分解为三个子问题:
三种角色:Leader(领导者,处理客户端请求)、Follower(追随者,被动响应)、Candidate(候选人,参与选举)
Leader选举:Follower超时未收到Leader心跳后转为Candidate,发起选举请求,获得多数票后成为Leader
日志复制:Leader接收客户端请求后,将日志复制给Follower,多数节点确认后提交
容错:Raft容忍(N-1)/2台节点故障。5节点容忍2台故障,3节点容忍1台故障
🔗其他一致性协议
ZAB协议:Zookeeper Atomic Broadcast协议。基于Raft思想设计,包括崩溃恢复和消息广播两种模式。用于保证Zookeeper分布式一致性
Gossip协议:流言协议。节点随机选择其他节点交换信息,最终达到一致。优点:扩展性好、去中心化;缺点:最终一致性、消息延迟。适用:大规模集群、Dynamo/Cassandra
常考点:Raft容忍(N-1)/2台故障,即N节点集群最多允许(N-1)/2台节点宕机仍能正常工作。3节点容忍1台,5节点容忍2台。
Raft 节点状态转换图
Follower
追随者
追随者
→
超时未收到
Leader心跳
Leader心跳
Candidate
候选人
候选人
→
获得
多数票
多数票
Leader
领导者
领导者
Leader 定期发送心跳 → Follower 保持追随|选举超时 → Candidate 发起投票
分布式事务-2PC/3PC
核心考点📋两阶段提交(2PC)
2PC是最经典的分布式事务协议,通过一个协调者(Coordinator)和多个参与者(Participant)完成。
| 阶段 | 协调者行为 | 参与者行为 |
|---|---|---|
| 第一阶段:准备阶段 | 向所有参与者发送Prepare请求,询问是否可以提交 | 执行事务操作但不提交,将Undo/Redo日志写入磁盘,返回Yes/No |
| 第二阶段:提交阶段 | 如果所有参与者都返回Yes,发送Commit请求;否则发送Rollback请求 | 收到Commit则正式提交事务;收到Rollback则回滚事务 |
2PC 两阶段提交流程图
协调者
参与者
参与者
———— 第二阶段 ————
协调者
参与者
⚠️2PC的缺点
同步阻塞:参与者在等待协调者响应期间处于阻塞状态,无法执行其他操作
单点故障:协调者宕机将导致参与者一直处于锁定状态
数据不一致风险:如果第二阶段网络异常,部分参与者收到Commit而部分未收到,导致数据不一致
📋三阶段提交(3PC)
| 阶段 | 名称 | 说明 |
|---|---|---|
| 第一阶段 | CanCommit | 协调者询问参与者是否可以执行事务(不执行实际操作) |
| 第二阶段 | PreCommit | 参与者执行事务但不提交(类似2PC的Prepare) |
| 第三阶段 | DoCommit | 协调者确认提交,参与者正式提交 |
3PC的改进:相比2PC,3PC引入了超时机制和CanCommit阶段,降低了阻塞风险和单点故障影响。但3PC仍然存在网络分区时的数据不一致风险,实际使用较少。
分布式事务-补偿型方案
高频📌TCC(Try-Confirm-Cancel)
Try阶段:业务检查和资源预留。检查业务是否可执行,并预留所需资源。例如:冻结账户余额
Confirm阶段:确认执行业务。使用Try阶段预留的资源执行实际操作。例如:扣除已冻结的余额
Cancel阶段:取消执行,释放资源。当Try或Confirm失败时调用。例如:释放已冻结的余额
📋Saga模式
核心思想:将长事务拆分为多个本地短事务,每个短事务都有对应的补偿操作。如果某一步失败,则依次执行前面所有步骤的补偿操作
执行流程:T1 → T2 → T3 → ... → Tn,如果Ti失败,则执行Ci-1 → Ci-2 → ... → C1(补偿操作逆序执行)
协调方式:编排式(Orchestration,中心化协调器)和 协同式(Choreography,事件驱动)
适用场景:跨系统的长业务流程,如电商订单(创建订单→扣库存→支付→发货)
TCC vs 2PC:TCC是业务层的补偿机制,需要业务方实现Try/Confirm/Cancel三个接口;2PC是数据库层的协议,由数据库自动完成两阶段提交。TCC性能更好但开发成本更高。
其他分布式事务方案
常考📝本地消息表
原理:在业务数据库中创建一张消息表,将业务操作和消息记录放在同一个本地事务中。定时任务扫描消息表发送消息
优点:实现简单、可靠,利用本地事务保证一致性
缺点:消息表与业务数据耦合、侵入业务逻辑
📨事务消息(RocketMQ)
半消息(Half Message):消息先发送到MQ但不投递给消费者,对消费者不可见
执行本地事务:生产者执行本地业务逻辑
消息回查:如果MQ未收到确认,定时回查生产者本地事务状态,根据结果决定Commit或Rollback消息
本质:本地消息表的MQ实现,利用两阶段提交思想
📡最大努力通知
原理:主动方按特定规则多次通知被动方,直到被动方确认收到为止
策略:递增间隔重试(1min→5min→30min→1h→...),超过最大次数后停止
适用:对一致性要求不高的场景,如支付结果通知
📊分布式事务方案对比
| 方案 | 一致性保证 | 性能 | 复杂度 | 适用场景 |
|---|---|---|---|---|
| 2PC | 强一致 | 低(同步阻塞) | 中 | 跨数据库事务 |
| 3PC | 强一致 | 中 | 高 | 改进版2PC |
| TCC | 最终一致 | 高 | 高(业务侵入) | 对性能要求高的核心业务 |
| Saga | 最终一致 | 高 | 中 | 长业务流程 |
| 本地消息表 | 最终一致 | 中 | 低 | 简单消息可靠投递 |
| 事务消息 | 最终一致 | 中 | 中 | RocketMQ生态 |
| 最大努力通知 | 最终一致 | 高 | 低 | 通知类业务 |
分布式缓存
高频💾Redis核心知识
数据结构:String(字符串/计数器)、List(列表/队列)、Set(集合/去重)、Hash(哈希/对象)、ZSet(有序集合/排行榜)
持久化:RDB(定时快照,恢复快但可能丢数据)、AOF(记录每条写操作,数据更安全但文件大)
集群模式:单机→主从复制→Sentinel(哨兵)高可用→Cluster分布式集群
🔴缓存三大问题对比
| 问题 | 定义 | 原因 | 解决方案 |
|---|---|---|---|
| 缓存穿透 | 查询缓存和数据库中都不存在的数据 | 恶意攻击或数据不存在 | ①布隆过滤器拦截 ②缓存空值(设置短过期时间) |
| 缓存击穿 | 单个热点Key过期瞬间,大量请求打到数据库 | 热点Key集中过期 | ①互斥锁(只允许一个线程重建缓存) ②热点Key永不过期 |
| 缓存雪崩 | 大量Key同时过期或Redis宕机 | Key集中过期或Redis故障 | ①设置随机过期时间 ②多级缓存 ③Redis集群高可用 |
🔄缓存一致性策略
| 策略 | 读操作 | 写操作 | 特点 |
|---|---|---|---|
| Cache Aside(旁路缓存) | 先读缓存,未命中则读DB并写入缓存 | 先更新DB,再删除缓存 | 最常用,可能出现短暂不一致 |
| Read Through(读穿透) | 缓存负责加载数据 | — | 缓存层封装数据加载逻辑 |
| Write Through(写穿透) | 正常读缓存 | 同时写缓存和DB(同步) | 数据一致性高,写性能较低 |
| Write Behind(写回) | 正常读缓存 | 只写缓存,异步写DB | 写性能最高,但有数据丢失风险 |
高频考点:Cache Aside策略中,更新数据时应该先更新DB再删除缓存(而非更新缓存),因为先更新缓存再更新DB可能导致并发时缓存中是旧数据。
消息队列
高频📊消息队列三大产品对比
| 对比维度 | Kafka | RabbitMQ | RocketMQ |
|---|---|---|---|
| 开发语言 | Scala/Java | Erlang | Java |
| 协议 | 自定义TCP协议 | AMQP | 自定义协议 |
| 吞吐量 | 极高(百万级/秒) | 中等(万级/秒) | 高(十万级/秒) |
| 消息可靠性 | 高(持久化+复制) | 高(持久化+确认机制) | 高(持久化+重试) |
| 特色功能 | 高吞吐、流处理 | 灵活路由、延迟消息 | 事务消息、顺序消息 |
| 适用场景 | 日志收集、大数据、流处理 | 业务消息、任务队列 | 电商交易、金融系统 |
🎯消息队列核心应用场景
异步处理:将同步调用转为异步消息,提升响应速度。例如:用户注册后异步发送欢迎邮件
应用解耦:生产者和消费者通过消息队列解耦,互不影响。例如:订单系统与库存系统通过MQ解耦
流量削峰:将突发流量暂存于消息队列,消费者按处理能力消费。例如:秒杀活动
日志处理:集中收集和存储日志数据。例如:ELK通过Kafka收集日志
选型建议:追求极致吞吐量选Kafka;需要灵活路由和消息可靠性选RabbitMQ;Java生态且需要事务消息选RocketMQ。
章节测验
15题🌐 第五章 · 分布式系统
第 1/15 题