news 2026/9/13 10:43:28

DDIA 导读(九):一致性与共识

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DDIA 导读(九):一致性与共识

本文是《Designing Data-Intensive Applications》(DDIA,中文译名《数据密集型应用系统设计》)第 9 章的导读。DDIA 是 Martin Kleppmann 所著的分布式系统经典,本系列逐章导读,把书的核心概念讲清楚。

一句话主旨

分布式系统的"一致性"有两层意思,别混淆——一是"副本之间的数据一致性"(多个副本读到同样的值),二是"共识"(一群节点对某个决定达成一致)。本章把两者拧在一起:要实现强一致性(线性一致性),就需要共识协议(Raft/Paxos);而共识协议在网络分区时必须牺牲可用性——这就是 CAP 定理的根源。这章是全书最硬、价值最高的钉子户,因为它解释了"为什么分布式系统没有银弹"。


核心概念拆解

1. 先分清两种"一致性"

这是读本章的第一个障碍——中文都叫"一致性",英文不同,含义不同:

一致性(Consistency, 副本一致性)共识(Consensus)
问什么“多个副本读到一样的值吗?”“一群节点对某个决定达成一致了吗?”
范围数据复制(第 5 章)决策达成(选主、提交、配置变更)
关系强一致性(线性一致)需要共识来保证共识是手段,一致性是目的

CAP 里的 C 是副本一致性(线性一致性),不是 ACID 里的 C(业务约束一致性)。这两个 C 完全不同,是分布式系统术语最坑的混淆点。ACID 的 C 是应用层不变量;CAP 的 C 是"读总是看到最新写"的强一致。

2. 线性一致性(Linearizability)——最强的副本一致性

直觉:尽管有多个副本和并发操作,系统看起来就像"只有一个副本"——每个操作在某个瞬时点原子完成,所有观察者看到同一个全局顺序。

非线性: 可能看到旧值

写X=1 @t=10

读X=0 @t=15
(读到落后副本的旧值)

线性一致: 看起来像单一副本

写X=1 @t=10

读X=1 @t=15
(看到新值)

读X=1 @t=20
(看到新值)

线性一致性的代价:要保证"读看到最新写",读写都要涉及多数派(quorum),不能只读本地副本。这意味着每次操作都有跨节点通信延迟,且网络分区时无法满足(少数派节点无法凑够 quorum,只能拒绝服务 → 牺牲可用性)。

第 5 章的 Quorum(w+r>n)是实现线性一致性的基础,但 Quorum 本身不够——还要保证读到的最新版本能被识别(不能读到"旧但凑够 r 的版本"),这需要共识协议协调。所以线性一致性需要在 Quorum 基础上协调版本顺序。

3. 因果一致性——比线性弱,但不需共识

直觉:不保证全局单一顺序,但保证"有因果关系的操作按因果序可见"。无因果关系的并发操作,不同观察者看到的顺序可以不同。

因果

发送消息A

回复消息B(因A而生)

发送消息C(与A并发)

  • A→B 有因果:所有观察者必须先看到 A 再看到 B
  • A 和 C 并发:有人可以先看到 C 再看到 A,可以

因果一致性不需要共识(只靠逻辑时钟/版本向量追踪因果),所以在网络分区时仍可用——这是它的优势。但实现复杂度高,很多系统默认不做(要么接受线性要么接受最终一致)。

4. CAP 定理——被滥用但核心正确

CAP 的准确表述:在网络分区(Partition)发生时,你只能在一致性(C,线性一致性)和可用性(A)之间二选一

要C: 凑不够quorum就拒绝服务

要A: 继续服务但可能不一致

网络分区 Partition 发生

选择?

CP系统
拒绝读写直到分区恢复

AP系统
继续读写, 分区恢复后修复

关键澄清(CAP 最常被误解的点)

  • CAP 只在网络分区时要求二选一。没有分区时,C 和 A 可以同时有。
  • CAP 的 C 是线性一致性,不是 ACID 的 C,也不是"最终一致性"。
  • CAP 不是"三选二",是"分区时 C 和 A 选一个"。平时三个都能要。
  • 分区不算罕见(网络抖动、节点宕机、GC 停顿都算分区),所以现实里更多是 PACELC:无分区时也要在延迟(L)和一致性(C)间权衡。

PACELC 更贴近现实:P(分区)时选 A 还是 C;E(else,无分区)时选 L(低延迟)还是 C(强一致)。元数据系统通常选 PC+EC(分区时选一致牺牲可用,平时也选一致牺牲延迟——元数据不能丢);数据/检索层通常选 PA+EL(分区时选可用,平时选低延迟——检索要快不要等 quorum)。两个选择都正确,因为服务的对象不同:元数据错不起,检索慢不起。

5. 共识协议——Raft / Paxos

共识要解决的问题:一群节点对某个值/决定达成一致,即使有节点宕机、网络延迟/分区。这是分布式系统最核心的难题。

最常见的共识任务:选主(Leader Election)——多个节点就"谁是 Leader"达成一致。

Raft——现代共识协议,易理解

直觉:一个 Leader 接收所有写,把日志复制到 Followers,靠"多数派确认"提交。Leader 挂了,多数派选新 Leader。

Follower3(挂了)Follower2Follower1Leader客户端Follower3(挂了)Follower2Follower1Leader客户端par[并行复制]多数派(3节点中2个)确认, 提交挂了, 不影响(多数派不含它)写请求写本地日志(term=5, index=7)AppendEntries(term=5)AppendEntries(term=5)确认确认成功

Raft 的关键机制

① Term(任期):时间被分成 term,每个 term 最多一个 Leader。term 号单调递增,是 Raft 的"逻辑时钟"——过期的 Leader(旧 term)的请求会被拒绝。

② 选主:Leader 挂了,Follower 超时未收到心跳 → 自己变 Candidate,term+1,向其他节点拉票。获得多数派票就成新 Leader。

③ 日志复制:Leader 把写操作写入日志,复制到 Followers,多数派确认后提交(commit)。已提交的日志保证不丢(只要多数派存活)。

④ 安全性:Raft 保证"已提交的日志在新 Leader 上一定存在"——选主时,Candidate 的日志必须至少和多数派一样新,否则选不上。这保证了 committed 日志不丢。

共识协议要求多数派确认,在资源紧张/网络问题时凑不够多数派,系统就会卡住或拒绝服务。这是 CP 设计的预期行为——强一致性系统宁可不可用也不冒不一致风险。理解这点,遇到"系统卡住但重启后恢复"的情况,就知道可能是共识协议在压力下的超时卡住,而非数据损坏。

问题→方案:问题——分布式环境下节点会宕机、网络会分区,如何让多个节点对同一个决定达成一致。场景——选主、日志提交、跨节点事务,都需要"多数同意才算数"。方案——共识协议(Raft/Paxos):Leader 接收写请求,复制到多数派确认后提交,Leader 挂了多数派重选举。代价是网络分区时凑不够多数派就拒绝服务(CAP 的 CP 选择)。线性一致性需要在 Quorum 基础上协调版本顺序;因果一致性是更弱的替代,不需共识但实现复杂。

Paxos——经典但难懂

Raft 是为"易理解"设计的,Paxos 是 Raft 之前的经典协议,数学上优雅但出了名难懂。不需要懂 Paxos 细节,只需知道:Raft 和 Paxos 解决同一个问题(共识),Raft 是 Paxos 的工程化简化版,现代系统(etcd、Consul 等)大多选 Raft。

6. 两阶段提交(2PC)——跨节点事务的原子提交

直觉:一个事务要写多个节点,要么全提交要么全回滚。2PC 用一个协调者(Coordinator)分两阶段:

节点2节点1协调者节点2节点1协调者阶段1: 准备(Prepare)阶段2: 提交(Commit)准备提交?(锁资源, 写预提交日志)准备提交?同意同意正式提交正式提交完成完成

2PC 的致命弱点——协调者故障:阶段 1 后、阶段 2 前,协调者挂了 → 节点们锁着资源等指令,不知道该提交还是回滚 →阻塞。这就是 2PC 的"阻塞问题"。

2PC 是解决跨节点事务的标准方案,但它的协调者单点和阻塞是已知缺陷。现代系统用 Raft 让协调者本身也高可用(如改进版 2PC + 共识选协调者)来缓解。


Mermaid:CAP / PACELC 决策

数据不能错

服务不能停

无分区时(E): L还是C?

EC: 要强一致, 接受延迟
元数据写入

EL: 要低延迟, 接受弱一致
检索读

网络分区/资源压力发生

选C还是A?

CP: 牺牲可用性
凑不够quorum拒绝服务

AP: 牺牲一致性
继续服务, 恢复后修复


章末分层诊断框架(本系列补充,非原书内容)

遇到"分布式系统在异常下卡住/崩溃"时,用这个框架诊断:

  • 是底层共识协议没收敛?(如选主卡住,凑不够多数派)→ 等网络/资源恢复或重启节点重选举
  • 还是上层状态机逻辑有缺陷?(如分配/重平衡逻辑死循环)→ 修应用逻辑或排查应用逻辑

两者症状相似(都表现为"卡住/拒绝服务"),但根因和修法不同。底层共识卡住通常是资源/网络问题,重启可恢复(状态没坏);上层逻辑缺陷可能需要修代码或排查应用逻辑。


下一篇:第 10 章——批处理。进入第三部分(派生数据),从"分布式理论"转向"数据怎么用批/流/集成串起来"。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 10:42:30

变压器励磁模型与电压暂降分析的Simulink实现

1. 变压器励磁模型的基础原理与Simulink实现变压器励磁模型是电力系统仿真中的核心组件,它直接影响着电压暂态过程的模拟精度。在Matlab/Simulink环境下,我们通常采用非线性电感模型来表征励磁特性,其本质是描述铁芯磁化曲线的饱和效应。1.1 …

作者头像 李华
网站建设 2026/9/13 10:41:57

Nuclei Templates 完整实战:用 11,000 个模板跑通漏洞扫描

Nuclei Templates 完整实战:用 11,000 个模板跑通漏洞扫描 【免费下载链接】nuclei-templates Community curated list of templates for the nuclei engine to find security vulnerabilities. 项目地址: https://gitcode.com/GitHub_Trending/nu/nuclei-templat…

作者头像 李华
网站建设 2026/9/13 10:41:38

Hermes 编程助手接入 Hindsight:为你的代码库构建跨会话持久记忆

Hermes 编程助手接入 Hindsight:为你的代码库构建跨会话持久记忆 【免费下载链接】hindsight Hindsight: Agent Memory That Learns 项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight 每次 AI 编码会话都从零开始?Hermes 编程…

作者头像 李华
网站建设 2026/9/13 10:40:44

Python实现轻量级日志实时监控与告警系统

1. 项目概述在服务器运维和系统管理中,日志监控是最基础也最重要的环节之一。传统的日志检查方式需要人工定期查看日志文件,不仅效率低下,而且无法及时发现突发问题。我在管理十几台生产服务器时,就曾因为未能及时发现磁盘爆满的警…

作者头像 李华