Skip to content

分布式理论

概念

分布式系统是指多台计算机通过网络协同工作,对外表现为一个整体的系统。核心挑战在于:网络不可靠、节点可能宕机、时钟无法完全同步。

关键术语

术语含义
节点(Node)分布式系统中的一台独立机器或进程
分区(Partition)网络故障导致节点之间无法通信
副本(Replica)同一份数据的多个拷贝,用于容错和提升读性能
共识(Consensus)多个节点就某个值达成一致的过程
幂等性(Idempotency)同一操作执行多次与执行一次效果相同

核心原理

1. CAP 定理

CAP 由 Eric Brewer 于 2000 年提出,指出分布式系统无法同时满足以下三个特性,最多只能满足其中两个:

  • C(Consistency,一致性):所有节点在同一时刻看到的数据完全一致(强一致性)
  • A(Availability,可用性):每个请求都能收到响应(不保证数据是最新的)
  • P(Partition Tolerance,分区容错):网络发生分区时,系统仍能继续运行

为什么 P 必须选?

在真实的分布式环境中,网络分区是客观存在且无法完全避免的——网线故障、交换机宕机、跨机房延迟都可能造成分区。放弃 P 意味着系统在网络抖动时直接停止服务,这在生产环境中不可接受。因此 P 是必选项,真正的选择只在 CP vs AP

CP vs AP 系统举例

类型代表系统行为
CPZooKeeper、etcd、HBase网络分区时拒绝写请求,保证数据一致
APEureka、Cassandra、CouchDB网络分区时仍接受读写,允许数据短暂不一致

ZooKeeper 选择 CP:Leader 选举期间集群不可用,但数据强一致,适合配置中心、分布式锁。

Eureka 选择 AP:节点故障时不下线其他节点的注册信息,优先保证服务发现可用,适合微服务注册中心。


2. BASE 理论

BASE 是对 CAP 中 AP 方向的工程实践总结,由 eBay 架构师 Dan Pritchett 提出:

  • Basically Available(基本可用):允许响应时间变长或部分功能降级,核心功能仍然可用
  • Soft State(软状态):系统中的数据可以存在中间状态,不要求时刻一致
  • Eventually Consistent(最终一致性):数据在一段时间后会最终达到一致状态

BASE vs ACID 对比

维度ACIDBASE
适用场景单机/强一致性关系数据库分布式/高可用系统
一致性要求强一致性最终一致性
可用性发生冲突时可能阻塞优先保证可用性
代表系统MySQL、PostgreSQLDynamoDB、Cassandra
核心思想事务要么全做要么全不做接受短暂不一致,换取高可用

3. 一致性模型

从强到弱,常见的一致性模型如下:

模型定义代价典型应用
强一致性写完之后所有节点立即可见最新数据延迟高,可用性低ZooKeeper、etcd
顺序一致性所有节点看到的操作顺序相同,但不要求实时中等早期分布式数据库
因果一致性有因果关系的操作按顺序可见,无关操作可乱序较低MongoDB(因果会话)
最终一致性在没有新更新的前提下,数据最终会收敛一致最低DNS、Cassandra、S3

4. Paxos 算法

Paxos 是经典的分布式共识算法,由 Leslie Lamport 提出。

三种角色

  • Proposer(提案者):发起提案,请求集群就某个值达成共识
  • Acceptor(接受者):投票接受或拒绝提案
  • Learner(学习者):学习最终被接受的值,不参与投票

两阶段流程

阶段一:Prepare(准备阶段)

  1. Proposer 生成全局唯一编号 n,向多数派 Acceptor 发送 Prepare(n) 请求
  2. Acceptor 收到后,若 n 大于已见过的最大编号,则承诺不再接受编号小于 n 的提案,并返回已接受的最大编号提案

阶段二:Accept(接受阶段)

  1. Proposer 收到多数派响应后,选取编号最大的已接受值(若无则用自己的值),发送 Accept(n, value)
  2. Acceptor 若未承诺更高编号,则接受该提案并通知 Learner

Multi-Paxos

Basic Paxos 每次共识都需要两轮 RPC,开销较大。Multi-Paxos 优化:选出一个稳定的 Leader,后续日志直接跳过 Prepare 阶段,只执行 Accept,大幅减少通信轮次。


5. Raft 算法

Raft 由 Diego Ongaro 和 John Ousterhout 于 2014 年提出,目标是比 Paxos 更易理解,被 etcd、TiKV、CockroachDB 广泛采用。

三种状态

  • Follower(跟随者):被动接收 Leader 的日志和心跳
  • Candidate(候选者):发起选举时的临时状态
  • Leader(领导者):负责处理所有客户端请求,复制日志

Leader 选举过程(ASCII 图)

初始状态:所有节点均为 Follower

  Node A [Follower]    Node B [Follower]    Node C [Follower]
      |                    |                    |
      |  超时未收到心跳      |                    |
      |                    |                    |
      v                    |                    |
  Node A [Candidate]       |                    |
      |                    |                    |
      |--- RequestVote(term=1) -->              |
      |--- RequestVote(term=1) ----------------->
      |                    |                    |
      |<-- VoteGranted ----                     |
      |<-- VoteGranted ----------------------------
      |                    |                    |
      v  获得多数票         |                    |
  Node A [Leader]          |                    |
      |                    |                    |
      |--- Heartbeat ------>                    |
      |--- Heartbeat -------------------------------->

日志复制流程

  1. 客户端向 Leader 发送写请求
  2. Leader 将日志条目追加到本地日志,并并行发送 AppendEntries 给所有 Follower
  3. 多数派(Quorum)写入成功后,Leader 提交该条目并应用到状态机
  4. Leader 在下次心跳中通知 Follower 提交

安全性保证

  • 选举限制:只有拥有最新日志的节点才能成为 Leader(日志比较:term 更大,或 term 相同但 index 更大)
  • 任期(Term):全局单调递增的逻辑时钟,用于检测过时信息

实际应用

系统用途
etcdKubernetes 集群元数据存储
TiKVTiDB 的分布式存储层
CockroachDB分布式 SQL 数据库
Consul服务发现与配置中心

6. ZAB 协议

ZAB(ZooKeeper Atomic Broadcast)是 ZooKeeper 专用的一致性协议,与 Raft 思路相近但有所不同。

核心流程

  • 崩溃恢复(Leader Election):Leader 宕机后,选出拥有最新 zxid(事务 ID)的节点作为新 Leader
  • 消息广播(Broadcast):类似两阶段提交,Leader 向所有 Follower 广播 Proposal,收到多数 ACK 后提交

ZAB vs Raft 对比

维度ZABRaft
设计目标ZooKeeper 专用通用共识算法
日志提交Follower 可不存完整历史必须有完整日志才能成为 Leader
顺序保证严格有序(FIFO)严格有序
易理解性较复杂更清晰,有完整论文

7. 一致性哈希

一致性哈希(Consistent Hashing)解决了传统取模哈希在节点增删时导致大量数据迁移的问题。

哈希环

将哈希空间组织成一个首尾相接的环(),节点和数据都映射到环上:

              0
           /     \
      300       60
   [NodeC]       [NodeA]
      |               |
     240           120
          [NodeB]
             180

数据按顺时针方向找到第一个节点进行存储。新增或删除节点时,只影响该节点相邻的数据,其余数据不受影响。

虚拟节点解决数据倾斜

真实部署中,节点数量少时哈希环分布不均,导致数据倾斜(某些节点负载远高于其他节点)。

解决方案:为每个物理节点创建多个虚拟节点(Virtual Node),分散映射到环上:

物理节点 NodeA → 虚拟节点 NodeA#1, NodeA#2, NodeA#3 ... 均匀分布在环上

虚拟节点数量越多,数据分布越均匀,通常每个物理节点配置 100~200 个虚拟节点。

实际应用

系统用途
Cassandra数据分片与副本放置
Amazon DynamoDB分区键路由
Nginx(一致性哈希模块)负载均衡
Memcached 客户端缓存节点路由

8. 分布式时钟

在分布式系统中,物理时钟无法做到完全同步(网络延迟、晶振漂移等原因),因此无法仅靠物理时间判断事件的先后顺序。逻辑时钟和混合时钟的目标是在不依赖绝对物理时间的前提下,准确追踪事件的因果关系。

Lamport Clock(兰伯特时钟)

  • 标量逻辑时钟,每个进程维护一个单调递增的计数器
  • 规则:本地事件发生时计数器加一;发送消息时附带当前计数器值;接收消息时取 max(本地计数器, 消息计数器) + 1
  • 局限:可以判断"先发生(happened-before)"关系,但无法区分并发事件——如果 a → bC(a) < C(b),但 C(a) < C(b) 不能推出 a → b

Vector Clock(向量时钟)

  • 每个进程维护一个长度为 N(进程数)的计数器向量
  • 既能判断因果关系,又能检测并发事件(两个事件互相不能比较大小即为并发)
  • DynamoDB、Riak 使用向量时钟进行冲突检测
  • 缺点:空间复杂度 ,进程数增加时开销显著

HLC(Hybrid Logical Clock,混合逻辑时钟)

  • 结合物理时间戳与逻辑计数器:物理时间提供粗粒度排序,逻辑计数器提供细粒度因果追踪
  • 与物理时间的偏差有上界,表示紧凑(
  • CockroachDB、YugabyteDB 采用 HLC
  • 优势:在保持因果追踪能力的同时,与真实时间的偏差可被控制在毫秒级

三种时钟对比

时钟类型能否判断因果能否检测并发空间复杂度典型应用
Lamport ClockO(1)简单排序场景
Vector ClockO(N)DynamoDB、Riak
HLC部分O(1)CockroachDB

9. FLP 不可能定理

结论:在异步系统中,即使只有一个进程可能发生故障,也不存在确定性的共识算法能保证在有限时间内终止。

工程含义:所有实际的共识算法(Paxos、Raft)都依赖超时机制和随机化来取得进展。FLP 定理告诉我们异步共识的理论极限,但实践中纯异步系统极为罕见,超时机制让算法在大多数情况下能正常工作。


10. ZooKeeper vs etcd 选型对比

ZooKeeper 和 etcd 都是分布式协调服务,提供强一致性的配置存储、服务发现和分布式锁能力,但在协议、数据模型和生态上存在明显差异。

架构对比

维度ZooKeeperetcd
语言JavaGo
一致性协议ZABRaft
数据模型树形(类文件系统,ZNode)扁平 KV(键值对)
临时节点支持(Ephemeral Node)通过 Lease 实现
Watch 机制一次性触发,需重新注册持续 Watch,基于 Revision
事务支持Multi 操作Mini 事务(If-Then-Else)
性能读多写少场景优秀读写均衡
运维复杂度JVM 调优,相对复杂单二进制,运维简单
生态Hadoop/Kafka/HBase 生态Kubernetes/Cloud Native 生态

选型建议

  • 已有 Hadoop/Kafka 生态 → ZooKeeper
  • Kubernetes / 云原生项目 → etcd
  • 需要临时节点语义(如分布式锁)→ ZooKeeper 更自然
  • 追求运维简单 → etcd

ZooKeeper 分布式锁实现示例

1. 客户端在 /locks/resource 下创建临时顺序节点 /locks/resource/lock-000001
2. 获取 /locks/resource 下所有子节点,排序
3. 如果自己是最小节点 → 获得锁
4. 否则 → Watch 前一个节点(如 lock-000000)
5. 前一个节点删除(释放锁或会话超时)→ 收到通知,重新检查
6. 客户端断开连接 → 临时节点自动删除 → 锁自动释放

面试常问 & 怎么答

Q1: CAP 定理是什么?为什么不能同时满足?举例说明 CP 和 AP 系统

答题思路(1 分钟版本)

CAP 定理指出,分布式系统无法同时保证一致性(C)、可用性(A)、分区容错(P)三者,最多满足其二。

为什么不能三者兼得?假设节点 A 和 B 之间发生网络分区,此时向 A 写入数据,B 无法同步。如果要保证 C,就必须拒绝 B 的读请求,牺牲 A;如果要保证 A,B 继续提供服务,但数据可能过期,牺牲 C。两者无法同时满足。

由于网络分区在生产中不可避免,P 必须保留,真正的取舍只在 CP vs AP:

  • CP 系统:ZooKeeper——选举期间拒绝写入,保证强一致,适合配置中心、分布式锁。
  • AP 系统:Eureka——节点故障时保留旧注册信息,优先可用,适合服务发现。

Q2: Raft 算法的核心流程?Leader 选举怎么做?

答题思路(1 分钟版本)

Raft 将一致性问题分解为三个子问题:Leader 选举、日志复制、安全性。

Leader 选举:节点初始为 Follower,超过选举超时未收到 Leader 心跳后,自增 term 转为 Candidate,向其他节点发 RequestVote 请求。获得多数票后成为 Leader,并立即发心跳阻止新选举。

选举安全性:投票时节点只给"日志不比自己旧"的 Candidate 投票,确保 Leader 一定拥有所有已提交的日志。

日志复制:客户端写请求发给 Leader,Leader 追加日志后并行发给 Follower,多数派写成功后提交,回复客户端。


Q3: 一致性哈希是什么?虚拟节点解决什么问题?

答题思路(1 分钟版本)

一致性哈希将哈希空间构成一个环,节点和数据都映射到环上,数据顺时针找最近节点存储。好处是新增或删除节点时,只有相邻的少量数据需要迁移,其余不受影响——传统取模哈希在节点数变化时几乎所有数据都要重新分配。

虚拟节点解决数据倾斜问题:节点少时环上分布不均,负载集中在少数节点。为每个物理节点创建多个虚拟节点均匀散布在环上,使数据分布更均匀,负载更平衡。Cassandra 和 DynamoDB 都使用了这一机制。


Q4: 分布式时钟有哪些?解决什么问题?

答题思路(1 分钟版本)

分布式系统中物理时钟无法完全同步,需要逻辑时钟来确定事件的先后顺序。

三种主要方案:Lamport Clock 是最简单的标量时钟,能判断因果关系但无法检测并发事件;Vector Clock 为每个进程维护一个计数器向量,既能判断因果又能检测并发,DynamoDB 和 Riak 使用它来做冲突检测,但空间复杂度 O(N);HLC 混合逻辑时钟结合物理时间和逻辑计数器,CockroachDB 使用它,兼顾了紧凑表示和因果追踪。

实际选型:大多数分布式数据库使用 HLC,分布式存储系统使用 Vector Clock,简单场景用 Lamport Clock 足够。


Q5: ZooKeeper 和 etcd 怎么选?

答题思路(1 分钟版本)

两者都是分布式协调服务,核心区别在协议、数据模型和生态。

ZooKeeper 使用 ZAB 协议,树形数据模型,原生支持临时节点和一次性 Watch,是 Hadoop/Kafka 生态的标配。etcd 使用 Raft 协议,扁平 KV 模型,持续 Watch 基于 Revision,是 Kubernetes 的核心组件。

选型建议:大数据生态(Kafka、HBase)选 ZooKeeper;云原生/K8s 生态选 etcd;需要分布式锁且已有 ZK 则继续用 ZK;新项目追求运维简单选 etcd(Go 单二进制,无需 JVM 调优)。


看到什么就先想到这类

关键词 / 场景优先想到
分布式系统设计取舍CAP 定理,先判断 CP 还是 AP
高可用 vs 强一致BASE 理论,最终一致性
配置中心 / 分布式锁ZooKeeper(CP)、etcd(Raft)
服务注册发现Eureka(AP)、Consul(CP)
多节点如何达成共识Raft(工程常用)、Paxos(理论基础)
etcd / TiKV 内部原理Raft 算法
ZooKeeper 内部原理ZAB 协议
缓存 / 存储分片路由一致性哈希 + 虚拟节点
节点增删数据迁移代价一致性哈希(vs 取模哈希)
数据倾斜 / 热点虚拟节点,增加哈希环分布均匀度
数据库事务 vs 分布式存储ACID vs BASE 对比
事件排序 / 因果关系 / 并发检测分布式时钟(Lamport/Vector/HLC)
K8s 元数据 / 云原生服务发现etcd(Raft)
临时节点 / 一次性 WatchZooKeeper(ZAB)
异步系统共识的理论极限FLP 不可能定理