⚙️ 系统原理 🔗 一致性算法 🛡️ 故障容错

分布式系统
深度解析

从内部工作原理到经典难题,从 CAP 定理到 Raft 算法,一次搞清楚分布式系统的核心思想与工程实践。

向下探索
01 / 系统概述

什么是分布式系统?

多台独立计算机通过网络协同,对外表现为单一整体,共同完成超出单机能力的任务。

🖥️

单体架构

所有组件在同一进程,简单易调试,但单点故障即全局瘫痪,伸缩性差。

🌐

分布式架构

多节点通过网络通信,每个节点独立运行,共同完成业务,可水平扩展。

📈

水平扩展

增加节点数量扩展能力,理论上线性提升吞吐量,QPS 百万级成为可能。

🛡️

故障容错

部分节点故障不影响整体,系统继续运行并自动检测、隔离、恢复故障节点。

⚡ 分布式系统三大目标

📊
高可用
99.99% SLA,年宕机 < 52 分钟
🚀
可扩展
水平扩容,百万 QPS 处理能力
🔒
一致性
数据跨节点同步,避免数据冲突
02 / 内部工作原理

系统内部如何运作?

节点通信、服务发现、负载均衡、数据复制——完整工作流程拆解。

🔗 节点通信演示

▶ 点击上方按钮观察节点状态变化…

📡 服务发现机制

节点如何在集群中相互找到?

// 服务注册(Consul 示例) func Register(name, addr string, port int) { reg := &api.AgentServiceRegistration{ Name: name, // "order-service" Port: port, Check: &api.AgentServiceCheck{ HTTP: "http://" + addr + "/health", Interval: "10s", }, } consul.Agent().ServiceRegister(reg) }
核心组件:Consul / etcd / Zookeeper——提供注册表,支持健康检查与故障节点自动摘除。

⚖️ 负载均衡策略

流量如何分配到各节点?

策略原理场景
轮询依次分配同质节点
加权轮询按权重比例节点性能不等
最小连接选连接数最少长连接
一致性哈希哈希环映射缓存亲和
随机随机选节点简单场景

📦 RPC 通信完整流程

🖥️
客户端
调用本地Stub
📦
序列化
Protobuf/JSON
🌐
网络传输
TCP/HTTP2
📤
反序列化
还原参数
⚙️
服务端执行
调用真实方法
返回结果
序列化回传

💓 心跳检测

Leader 每 150ms 发送心跳。Follower 超过 election timeout (300~500ms) 未收到心跳,则发起新选举。

select { case <-heartbeatTimer.C: // 超时!发起选举 currentTerm++ state = Candidate startElection(currentTerm) case <-heartbeatCh: // 收到心跳,重置定时器 heartbeatTimer.Reset(randomTimeout()) }

📊 数据复制流程

1
写请求 → Leader
2
追加 Uncommitted 日志
3
并发复制至 Follower,等 Quorum 确认
4
日志 Committed,应用状态机
5
响应客户端 ✓ 写入成功
03 / 核心问题

会遇到哪些难题?

分布式系统的经典挑战,每一个都需要精心的工程设计来应对。

🌩️

网络分区(Network Partition)

CAP 中的 P,最难避免的物理故障

网络故障导致集群分裂,各子集无法感知彼此状态。此时在继续服务保证一致性之间必须二选一。

分区 A
N1
Leader
N2
分区 B
N3
N4
N5
✅ 集群正常,N1 为 Leader,5 个节点相互通信正常。
✓ Quorum✓ Raft/Paxos✓ 脑裂检测
👻

数据不一致(Data Inconsistency)

副本间数据在某时刻存在偏差

节点 A 写入 x=100,但节点 B 仍返回旧值 x=99,原因是异步复制存在延迟。最终一致性系统中"最终"有多快是关键。

T=0 → Client A 写入 Node1: x=100
T=1 → Node1→Node2 复制延迟 200ms
T=1 → Client B 读 Node2: x=99 ← 旧值!
T=2 → 复制完成,Node2: x=100 ✓
强一致性
写完即读到,需等多数派确认,高延迟
最终一致性
异步复制,低延迟,但短暂不一致
✓ 强一致读✓ 版本向量✓ 读写Quorum
🔁

重复请求与幂等性

网络重试导致操作被执行多次

客户端超时重试,但服务端已成功处理第一次请求:扣款两次、订单重复、库存超扣。

// 幂等 Key 保障 func CreateOrder(req OrderReq) Result { key := req.IdempotencyKey // 客户端生成UUID if r, ok := redis.Get(key); ok { return r // 返回已缓存结果 } result := db.Create(req) redis.SetEX(key, result, 24*time.Hour) return result }
✓ 幂等Key✓ Token机制✓ DB唯一约束

时钟漂移(Clock Skew)

各节点时钟无法精确同步

分布式系统无法依赖本地时钟判断事件先后。物理时钟可能相差数百毫秒,NTP 同步甚至可能造成时间倒退。

❌ 物理时钟
Node1: 10:00:01.000
Node2: 10:00:00.850
误差可达数百 ms
✅ 逻辑时钟
仅表示因果关系
T(e) > T(cause(e))
确保事件偏序
✓ Lamport时钟✓ 向量时钟✓ TrueTime
🔄

分布式死锁(Distributed Deadlock)

跨节点资源循环等待

Service A 持有 R1 等待 R2,Service B 持有 R2 等待 R1,形成跨节点循环等待,单机死锁检测无法发现。

Service A
持有R1 → 等待R2
Service B
持有R2 → 等待R1
✓ 锁超时✓ 死锁检测✓ 有序资源获取
🗡️

拜占庭故障(Byzantine Fault)

节点发出错误或恶意信息

节点可能被攻击并发送错误消息。普通 Raft/Paxos 假设节点宕机但不作恶,无法应对拜占庭故障。

✓ 忠诚节点
发送真实消息
✗ 叛徒节点
发送不一致消息
容忍 f 个叛徒需至少 3f+1 个节点,BFT 算法开销极高,主要用于区块链。
✓ PBFT✓ 数字签名✓ 区块链共识
04 / CAP 定理

CAP 三角,只能三选二

一致性(C)、可用性(A)、分区容错(P)——分布式系统永恒的权衡。

C 一致性 A 可用性 P 分区容错 CP 系统 AP 系统 CA 系统 不可能区域

选择你的权衡方向

⬅ 点击上方按钮,了解不同 CAP 选择的权衡与代表系统。

📊 一致性模型对比

级别定义延迟典型系统
强一致性 (Linearizable)写完立即所有节点可见,如同单机ZooKeeper, etcd, Spanner
顺序一致性全局操作有序,按程序顺序执行中高分布式锁服务
因果一致性有因果关系的操作保序,无关可乱序MongoDB Causal, Cassandra LWT
最终一致性最终所有副本收敛到相同值DynamoDB, Cassandra, Redis
读己写一致自己写的值自己能立即读到低-中MySQL 主从(读主库)
05 / 共识算法

Raft vs Paxos

多节点如何就某个值达成一致?共识算法是分布式系统的基石。

🗳️ Quorum 投票演示

点击节点投票,观察 Quorum 达成(需 N/2+1 票)。

总节点数5
故障节点0
已投票0
所需Quorum3
是否达成等待投票
Quorum 公式:W + R > N
若 W=R=N/2+1 则强一致;若 W=1,R=N 则写快读慢。

选举阶段 Leader Election

1

Follower 超时

election timeout 内未收到心跳,转为 Candidate,Term++。

2

广播 RequestVote

向所有节点发送投票请求,携带当前 Term 和日志信息。

3

获得多数票

超过半数节点投票(每 Term 每节点只投一票),成为新 Leader。

4

广播 AppendEntries

立即发送心跳,阻止其他 Candidate 发起选举。

日志复制 Log Replication

1

接收客户端写请求

Leader 追加 log entry,状态标记为 Uncommitted。

2

并发复制

通过 AppendEntries RPC 并发将日志发送给所有 Follower。

3

Quorum 确认

超过半数 Follower 响应 ACK,Leader 提交(Committed),更新 commitIndex。

4

应用状态机

应用 committed log,通知 Follower commit,响应客户端。

⚠️ Raft 安全性保证:同一 index 的不同 Term 日志不会被提交两次;committed 日志永不被覆盖;Log Matching Property 确保日志无分叉。

Phase 1: Prepare 阶段

1a

Proposer 发 Prepare(n)

选唯一递增提案号 n,向所有 Acceptor 广播 Prepare(n)。

1b

Acceptor 响应 Promise

若 n > minProposal,承诺不再接受更小提案,返回已接受的最大值。

Phase 2: Accept 阶段

2a

Proposer 发 Accept(n,v)

收到多数 Promise 后,选最大 acceptedN 的值(或自选值),广播 Accept。

2b

Acceptor 接受提案

若 n ≥ minProposal 则接受,通知 Learner。多数接受即共识达成。

🎭 三种角色

📤 Proposer(提议者)
发起提案,选择提案号,驱动整个 Paxos 流程。
✅ Acceptor(接受者)
核心角色,持久化状态,响应 Prepare/Accept,保证安全性。
👁️ Learner(学习者)
获知被选定的值,应用到本地状态机。
Paxos 只解决单值共识,Multi-Paxos 通过稳定 Leader 减少 Phase1 开销。Raft 是对 Paxos 的重新设计,更易理解和工程实现。
维度RaftMulti-PaxosZAB (ZooKeeper)
设计目标易理解、易实现理论证明完备高吞吐主备复制
Leader 选举随机超时 + TermPrepare 阶段竞争Fast Leader Election
日志复制强 Leader 驱动可多 ProposerLeader 广播
脑裂防护Term 编号提案号Epoch 编号
实现复杂度低(推荐)极高
代表系统etcd, TiKV, CockroachDBChubby, 部分存储ZooKeeper
06 / 分布式事务

跨服务的数据一致性

单机 ACID 无法跨越网络边界,分布式事务是最复杂的工程问题之一。

🔄 两阶段提交(2PC)

协调者(Coordinator)统一管理参与者(Participant)的提交与回滚。

Phase 1: Prepare
📡
协调者向所有参与者发送 Prepare
⚙️
参与者执行本地事务(不提交),写 undo/redo 日志,返回 Yes/No
Phase 2: Commit / Rollback
所有 Yes → 协调者发 Commit
任一 No → 协调者发 Rollback,全部回滚
⚠️ 2PC 经典问题:协调者宕机导致参与者永久阻塞;Phase2 网络故障造成部分节点提交部分未提交;协调者是全局单点。

🔗 SAGA 模式(微服务事务)

拆解为一系列本地事务,通过补偿操作(Compensating Transaction)实现回滚。

🎯 编排式 (Orchestration)
中央 Orchestrator 指挥各服务顺序执行,逻辑集中,便于监控,推荐复杂流程。
🔔 事件驱动 (Choreography)
各服务监听事件自主触发,去中心化松耦合,适合简单流程,但整体追踪难。
07 / 工程解决方案

核心工程实践与解法

经业界验证的稳定性模式,构建高可用分布式系统的工程基石。

🛡️ 熔断器(Circuit Breaker)

防止级联故障蔓延全系统
  • 关闭:正常通过,统计失败率
  • 打开:失败率超阈值,直接拒绝快速失败
  • 半开:定时放少量请求探测服务恢复
  • 代表:Hystrix, Resilience4j, Sentinel
// 状态机 Closed → (failRate>50%) → Open Open → (timeout 5s) → HalfOpen HalfOpen → (success) → Closed HalfOpen → (fail) → Open

⏬ 限流与降级

保住核心链路,牺牲非核心功能
  • 令牌桶:固定速率放令牌,允许突发
  • 漏桶:匀速处理,严格平滑流量
  • 滑动窗口:统计时间窗口内请求数
  • 降级策略:返回缓存/默认值/友好提示
  • 工具:Sentinel, Nginx limit_req, Redis

🔁 重试与超时

优雅处理瞬时故障,避免雪崩
  • 指数退避:间隔 = base × 2^n,避免惊群
  • Jitter(抖动):加随机量错开重试峰值
  • 超时设置:P99 延迟的 2~3 倍
  • 最大重试次数:通常 3 次,超出则熔断
  • 重试操作必须是幂等的

📨 消息队列解耦

异步化、削峰填谷、最终一致
  • 异步解耦:生产消费方独立扩缩容
  • 削峰填谷:流量突刺缓冲保护下游
  • 事务消息:本地事务+消息发送原子化
  • 至少一次投递:消费者做幂等处理
  • 代表:Kafka, RocketMQ, RabbitMQ

🔐 分布式锁方案对比

方案原理优点缺点场景
数据库行锁SELECT FOR UPDATE / 唯一索引简单性能差,易死锁低并发
Redis SETNX原子指令占锁+过期性能高,简单单点,锁超时误删高并发
Redis Redlock多数节点加锁容忍单点故障实现复杂,有争议高可靠要求
ZooKeeper有序临时节点+Watch强一致,自动释放性能差,运维成本高强一致
etcd 租约Lease + Watch + Raft强一致,云原生分区时可能阻塞K8s等

🔭 可观测性(Observability)

📊
Metrics(指标)
QPS、P99延迟、错误率、CPU/内存。Prometheus + Grafana
🔍
Tracing(链路追踪)
全链路 TraceID 串联,定位跨服务瓶颈。Jaeger, SkyWalking
📝
Logging(日志)
结构化日志,携带 TraceID。ELK Stack, Loki