分布式学习(二)
在上一篇博客中了解完为什么要有分布式系统,分布式系统解决了什么问题,又带来了哪些新的挑战后,在这一篇中就要正式开始学习分布式系统了
在本章中,将从分布式系统通信入手,介绍分布式系统中对一致性与可用性的权衡:CAP、BASE、最终一致性、中心化与去中心化、共识算法。
分布式系统通信机制
在分布式系统中,广播是一种非常常见的通信要求: 一个节点产生了某个信息,需要让其他节点都知道.
例如: 配置变更通知, 成员上下线, 路由表更新, 缓存失效, 状态同步, 元数据传播, 故障检测, 集群状态扩散等等
分布式系统通信在传播模型(信息如何在多个节点之间扩散)上有两种: 中心化广播和Gossip协议
中心化广播
中心化广播是有一个中心节点或中心组件负责把消息发给所有目标节点

如图,上图中的拓扑就是中心化广播的经典结构
中心化广播并不只有一种实现,常见有以下几类:
主节点广播: 集群中有一个Master 或Leader ,由它负责广播.
典型应用:
- Raft 中 Leader 向 Follower 复制日志
- ZooKeeper 中 Leader 广播事务
- HDFS NameNode 管理元数据
- 某些主从数据库复制
中心 Broker 广播: 消息不是由业务节点直接广播,而是交给中心消息中间件.
// 像这样
Producer -> Broker -> Consumer1
-> Consumer2
-> Consumer3
典型应用:
- Kafka
- RocketMQ
- RabbitMQ
- Pulsar
- Redis Pub/Sub
发布/订阅模型
中心化广播经常以发布/订阅形式出现.
Publisher 发布消息 Subscriber 订阅消息 中心组件负责分发
典型应用:
- 消息队列
- 事件总线
- 配置中心
- 注册中心
- 协调服务
中心化广播的工作原理
以一个配置中心为例:
- 管理员修改配置
- 配置中心保存新配置
- 配置中心向所有客户端广播配置变更
- 客户端收到通知后拉取最新配置
- 客户端应用新配置
Admin
|
v
Config Center
|
|------> App Instance 1
|------> App Instance 2
|------> App Instance 3
消息队列的流程是这样:
Producer
|
v
Broker
|
|------> Consumer Group A
|------> Consumer Group B
|------> Consumer Group C
中心化广播的优缺点
优点:
消息来源明确,所有消息都来自中心节点,所以
- 权限控制简单
- 审计方便
- 版本管理方便
- 数据权威性高
例如配置中心配置只能由 Config Center 发布
这样可以避免多个节点随意修改配置导致混乱。
容易保证顺序,如果所有消息都从中心节点发出,那么中心节点可以统一编号。
适合强管理场景
例如:
- 配置下发
- 任务分发
- 权限变更
- 集群调度
- 元数据管理
这些场景通常需要一个权威中心。
缺点:
中心节点是单点风险
中心节点压力大
扩展性受限
容易出现广播风暴
网络故障时恢复复杂
Gossip 协议
Gossip 协议也叫:
- 流言协议
- 谣言传播协议
- epidemic protocol,流行病协议
它的核心思想是:
节点之间随机互相通信,每个节点把自己知道的信息告诉其他节点,经过多轮传播后,整个集群最终都知道这个信息。
非常像现实中的“传谣言”:A 知道一个消息, A 告诉 B 和 C, B 告诉 D 和 E, C 告诉 F 和 G … 最后所有人都知道了

Gossip 没有强中心节点,每个节点既是信息接收者,也是信息传播者。
Gossip 的传播方式
Gossip有三种传播方式
PUSH模式:
发送方主动推送消息给邻居,实现简单,但可能产生冗余传输。
PULL模式:
接收方主动拉取未知消息,网络流量低,但收敛速度较慢。
BOTH模式(结合 push 和 pull):
双向交换状态,收敛最快,是实际应用中最常用的模式。
Gossip 协议的工作原理
可参考图中传播过程模拟
Gossip 的传播速度通常是指数级的。
假设每个节点每轮告诉 2 个节点:
第 0 轮:1 个节点知道 第 1 轮:3 个节点知道 第 2 轮:9 个节点知道 第 3 轮:27 个节点知道 第 4 轮:81 个节点知道
理论上,知道消息的节点数量会按指数增长。
所以在大规模集群中,Gossip 可以在较少轮次内让信息覆盖大部分节点。
例如 10000 个节点,可能只需要十几轮或几十轮就能基本传播完成。
Gossip 的收敛性
Gossip 通常提供的是:
最终一致性,而不是强一致性。
也就是说:某个时刻: A 知道 version = 42, B 还不知道, C 知道 version = 41
这是正常的。但只要网络最终可达,经过多轮交换,所有节点最终会收敛到相同状态。
Gossip 的常见用途
成员管理:
集群需要知道哪些节点存活。
节点 A 怀疑节点 B 宕机
A 把这个怀疑传播出去
其他节点收到后也增加对 B 的怀疑分数
当怀疑分数超过阈值,大家认为 B 下线
典型系统:
Cassandra Consul Redis Cluster Amazon Dynamo
故障检测:
Gossip 可以结合心跳和 phi accrual failure detector。
每个节点定期和其他节点通信
如果长时间收不到某节点消息
就标记为 suspect
再传播 suspect 信息
元数据传播:
例如:
- 节点地址
- 节点角色
- 数据分片信息
- 路由表
- 负载情况
- 版本号
状态同步:
例如:
每个节点维护一份集群状态
节点之间互相同步差异
最终所有节点状态一致
反熵 Anti-Entropy:
Gossip 常用于反熵,即修复节点之间的数据差异。
A 和 B 比较 Merkle Tree
发现某些 key 不一致
然后同步这些 key
Cassandra、Dynamo 等系统使用类似思想。
Gossip的优缺点
优点:
去中心化:无主节点,任意节点均可发起,系统鲁棒性极强。 容错性强:节点宕机或网络抖动不影响整体传播路径。 极高扩展性:O(log N) 轮即可覆盖全网,适合万级节点集群。
缺点:
最终一致:存在传播延迟,不适用于强一致性要求的场景。 网络冗余:节点可能多次收到同一消息,增加带宽消耗。 拜占庭容错:默认节点诚实,难以抵御恶意节点的信息污染。
分布式系统通信在具体实现上分为同步与异步两种
同步与异步主要关注的点在于 “调用方发出请求后,是否必须要等待结果才能继续执行?”
同步通信
调用方发出请求后,通常需要等待对方处理并返回结果,才能继续后续逻辑.
例如:
服务A调用服务B:
A: 请帮我查询订单
B:处理中
B:返回结果
A:拿到结果后继续执行
在整个过程中如果B没有返回结果,A就一直等待.
同步通信的优缺点
优点:
1.编程模型简单
同步调用符合人的直觉:
Result result = service.call();
if (result.isSuccess()) {
// 成功
} else {
// 失败
}
逻辑清晰,容易理解和调试。
2.可以立即得到结果
调用方可以马上知道成功还是失败,
3.适合强一致场景
缺点:
1.容易阻塞
2.耦合度高
调用方依赖被调用方的可用性
3.容易级联故障
一个下游服务慢,可能拖垮整个链路
异步通信
请求方发出请求后,不需要立即等待结果,就可以继续执行其他任务。结果稍后通过回调、通知、消息、轮询等方式获得。
例如:
服务A 发送消息给 服务B: A:请处理订单 A:我继续做别的事情 B:后台处理 B:处理完成后通知 A,或者 A 稍后查询结果
异步通信的优缺点
优点:
1.提高响应速度
把非核心逻辑放到后台处理
2.解耦系统
服务之间不直接调用,而是通过消息或事件通信
3.削峰填谷
高流量时,消息队列可以缓冲请求,避免数据库被瞬时流量打垮
4.提高可用性
某个下游服务故障,不一定影响主流程
缺点:
1.复杂度更高
异步系统需要处理很多问题:
- 消息丢失
- 消息重复
- 消费顺序
- 消费失败
- 重试策略
- 死信队列
- 幂等性
- 最终一致性
- 状态查询
2.不能立即知道结果
3.调试和排查困难
在了解完前置知识后,接下来介绍在分布式中非常重要的理论: CAP理论
CAP定理
CAP定理起源于 2000 年,由加州大学伯克利分校的 Eric Brewer 教授在分布式计算原理研讨会(PODC)上提出,因此 CAP 定理又被称作 布鲁尔定理(Brewer’s theorem)
2 年后,麻省理工学院的 Seth Gilbert 和 Nancy Lynch 发表了布鲁尔猜想的证明,CAP 理论正式成为分布式领域的定理。
CAP 定理讨论 Consistency(一致性)、Availability(可用性)和 Partition Tolerance(分区容错)。
一致性(Consistency):在 Gilbert/Lynch(2002)的证明语境里,CAP 的一致性 C 指的是 Atomic Consistency,通常等同于 Linearizability(线性一致性)。即所有操作按实时顺序线性化,即写操作一旦完成,后续所有读操作都必须返回该写入的值(或更新的值)。注意: 这里的 Consistency 与数据库 ACID 中的 Consistency(一致性约束)含义不同,后者指事务执行前后数据库状态满足完整性约束。
可用性(Availability):非故障的节点必须对每个请求返回响应(不讨论响应快慢)。注意:这是 CAP 理论中的严格定义,不包含工程中的延迟/SLA 指标(如「1s 内返回」)。
分区容错性(Partition Tolerance):CAP 里的 P 本质上是在假设异步网络(可能延迟/丢包/分区),不是一个你「选择要不要」的功能。真正的权衡是:当分区发生时,你必须在**线性一致(CAP 的 Consistency=Linearizability)与CAP-Availability(任何非故障节点都要对请求给非错误响应)**之间做选择。
什么是网络分区?
分布式系统中,多个节点之间的网络本来是连通的,但是因为某些故障(比如部分节点网络出了问题)某些节点之间不连通了,整个网络就分成了几块区域,这就叫 网络分区。
并非三选二,实为二选一
在很多描述中会把CAP定理描述为"一致性、可用性、分区容忍性三者你只能同时达到其中两个,不可能同时达成",但在实际应用中,网络分区是无法避免的,所以我们必须要满足分区容错性
为什么不可能选择CA架构
因为分布式系统离不开网络通信,而网络故障是常态:
- 心跳检测可能因网络抖动丢包,导致误判节点故障
- 数据同步过程中可能因包丢失导致不一致,系统为达成一致会不断重试,造成请求阻塞
因此,在异步网络模型下(分区可能发生),当分区发生时,必须在线性一致性与 CAP-可用性之间取舍。 能够保证 CA 的只有单机系统——因为只有一个节点,数据写入成功后所有请求都能看到相同数据;只要这个节点活着,系统就可用。
CP架构(一致性+分区容错)
- 发生分区时,拒绝服务(牺牲可用性),以保证数据一致。
- 典型系统:ZooKeeper、etcd、HBase、MongoDB(默认配置)
- 适用场景:金融交易、配置管理、分布式锁等对正确性要求极高的场景。
AP(可用性 + 分区容错)
发生分区时,继续提供服务(可能返回旧数据),以保证可用。
典型系统:Cassandra、DynamoDB、CouchDB、Eureka
适用场景:电商商品展示、社交动态、DNS 等对实时一致性要求不高的场景。
选择 CP 还是 AP 的关键在于当前的业务场景,没有定论:比如对于需要确保强一致性的场景如分布式锁、配置管理会选择 CP;对于高可用优先的场景如微服务注册中心会选择 AP。
CAP理论的适用范围
CAP 理论主要讨论单个数据对象在副本复制场景下的一致性与可用性权衡。
| 更贴近 CAP 讨论模型 | 需要拆分到分片/对象/操作级别分析 |
|---|---|
| Redis 主从/哨兵集群 | 业务系统(无状态服务) |
| MySQL 主从/多主集群 | Redis-Cluster(每个 shard 仍有副本) |
| MongoDB 副本集 | MongoDB-Cluster(分片 + 副本并存) |
| ZooKeeper、etcd | 分库分表(跨分片事务需额外协调) |
| Kafka、RocketMQ | 大多数微服务应用* |
说明:
- CAP 讨论模型:单个读写寄存器(single register)的副本复制语义
- 复杂系统:需要拆解到「每个对象/分区/操作」的一致性语义讨论
- 分片 + 副本:分片系统每个 shard 通常仍有副本复制,一致性与可用性权衡仍在
业务系统与 CAP 的深度关联:
业务系统本身虽不涉及副本同步,但深受底层组件 CAP 属性的影响。忽视这一点会导致系统在遭遇网络分区时发生级联雪崩(Cascading Failure)。
受 CAP 属性影响的业务场景:
业务场景 底层组件 CP 组件的影响 AP 组件的影响 RPC 路由 注册中心(如 Nacos CP 模式) 注册期间不可用,请求被拒绝 可能路由到已下线实例,需要重试 分布式锁 Redis(AP)/ ZooKeeper(CP) 性能较低但可靠 性能高但可能锁失效 限流熔断 Redis 计数器 可能读到旧计数,限流失效 同左 缓存更新 Redis 主从 主从切换时可能丢数据 同左 消息消费 Kafka 消费进度同步慢,重复消费 同左 实践建议:业务开发者虽然不需要「实践」CAP 理论,但必须理解 CAP 理论,以便:
- 为不同业务场景选择合适的组件(CP 或 AP)
- 理解所选组件在网络分区时的行为特征
- 设计符合业务需求的容错机制(重试、熔断、降级)
很多开发者认为自己在「实践 CAP 理论」,实际上只是站在已有组件上做选择(用 CP 还是 AP),而非真正实践该理论。真正需要实践 CAP 的是研发 Redis、MySQL 这类分布式存储组件的工程师。