分布式系统模式 收藏

  • 书籍语言:简体中文
  • 下载次数:5286
  • 书籍类型:Epub+Txt+pdf+mobi
  • 创建日期:2025-07-01 12:10:02
  • 发布日期:2025-09-07
  • 连载状态:全集
  • 书籍作者:乌梅什·乔希
  • 运行环境:pc/安卓/iPhone/iPad/Kindle/平板

内容简介

本书深入剖析了主流开源分布式系统模式,包括模式中的常见问题和解决方案,并展示了Kafka和Kubernetes等系统的真实代码示例,以帮助企业架构师和开发人员更好地理解这些系统的工作原理,以及分布式系统的设计原则,为应对数据存储在多台服务器上时可能出现的各种问题做好准备。
通过阅读本书,读者将:
了解什么是分布式系统,以及为什么需要分布式系统。
更深入地理解分布式系统模式设计所面临的挑战,以选择合适的云服务和产品。
理解包括数据库、内存数据网格、消息代理,以及各种云服务在内的系统的实现原理。
自信地浏览开源代码库,并清晰地看到模式和解决方案如何映射到如Kafka和Kubernetes这样的真实世界系统中。
本书对于分布式架构工程师以及想要构建自己的分布式系统的开发者来说,是一本有价值的参考书。

作者简介

Unmesh Joshi (乌梅什·乔希)软件架构领域的领军人物,Thoughtworks 首席顾问,拥有超过24年的IT行业经验。分布式系统领域的资深专家,对分布式系统的设计和实现有着深刻的理解,对分布式系统的架构模式有系统的梳理和总结。在 Scala、Akka、Kafka、Cassandra、Kubernetes、Docker和云服务等技术领域积累了丰富的经验,这些技术专长使他能够从理论到实践全面掌握分布式系统的核心问题。

编辑推荐

适读人群 :分布式系统架构工程师、软件开发者

介绍了在集群节点之间建立有效网络通信的技巧。

介绍了常用的分区方案,并深入研究两阶段提交协议的复杂性。

介绍了数据库中逻辑时间戳的使用,以帮助读者理解数据版本控制的基本概念。

阐述了Paxos和Raft等共识算法的构建块,以确保分布式系统中副本的一致性。

阐述了用于实现集群协调任务(如组成员资格、故障检测以及健壮的集群协调)的机制。

涵盖了数据复制模式、数据分区模式、分布式时间模式、集群管理模式以及节点间通信模式等内容。


下载地址

序言

本书写作缘由

在2017年,我参与了一个名为“Thirty Meter Telescope”(TMT)的大型光学望远镜软件系统的开发项目。我们的任务是构建供各个子系统使用的核心框架和服务。这些子系统组件必须能够相互发现与检测组件故障,并能够存储有关各组件的元数据。负责这些信息存储的服务必须是容错的。考虑到望远镜生态系统的特殊性,我们不能采用现成的产品和框架,只能从零开始,打造适用于不同软件子系统的核心框架和服务,从本质上说,我们要建立的是一个分布式系统。

我曾设计并构建过依赖于Kafka、Cassandra和MongoDB等产品的企业系统,它们使用AWS或GCP等云服务。这些产品和服务都是分布式的,解决了一系列相似的问题。对于TMT系统,我们必须自行开发解决方案。为了验证和比较这些成熟的产品,我们需要更深入地理解它们的内部机制。了解这些云服务和产品的构建方式及其背后的原因是必要的,它们的官方文档往往太过产品化,不利于达成我们的目标。

关于构建分布式系统的信息分散在各种研究论文中。然而,这些学术资源也有局限,它们往往只关注特定领域而忽略了相关主题。以“Consensus: Bridging Theory and Practice”(Ongaro,2014)这篇精彩的论文为例,它详细解释了实现Raft共识算法的过程。但你不会从中了解到像etcd这样的产品如何使用Raft来追踪集群成员资格和其他产品的相关元数据,如Kubernetes。Leslie Lamport的著名论文“Time, Clocks, and the Ordering of Events in a Distributed System”(Lamport,1978)中讨论了逻辑时钟的使用,但它并未解释像MongoDB这样的产品如何使用逻辑时钟作为版本号来控制数据的版本。

我相信编写代码是验证理解正确与否的最佳方式。正如Martin Fowler所说:“代码就像数学,我们必须消除其中的歧义。”因此,为了深刻理解分布式系统的基础模块,我决定自己动手构建这些产品的简化版本。我从打造一个玩具版的Kafka开始,一旦有了合理的版本,我就用它来探讨分布式系统的一些基本概念。这种方法被证明非常有效。为了验证通过代码来阐释概念的效果,我在Thoughtworks开展了一系列内部研讨会,这些研讨会对我帮助极大。因此,我将这种方法扩展到了Cassandra、Kubernetes、Akka、Hazelcast、MongoDB、YugabyteDB、CockroachDB、TiKV和Docker Swarm等产品。我提取了代码片段来理解这些产品的构建模块。果不其然,这些模块之间存在许多相似之处。几年前,我偶然与Martin Fowler讨论过这个话题,他建议我将其整理成模式。本书便是我与Martin Fowler合作,将分布式系统中的共通的构建模块整理成模式的成果。

本书读者

在当今软件架构和开发的选择丰富多样的背景下,面对众多分布式产品和云服务,架构师和开发者面临着复杂的设计抉择。这些产品和服务的设计折中可能难以直观理解。单凭阅读文档是远远不够的。比如,当我们考虑“AWS MemoryDB通过复制的事务日志确保了数据的持久性”“Apache Kafka现能独立于ZooKeeper运作”或者“Google Spanner通过同步的全球时间来维护外部一致性”这样的句子时,该如何理解这些技术性描述?

为了深入了解,专业人士往往依赖于产品供应商的认证培训。然而,这些认证大多局限于特定产品,关注的是表层特性,而非背后的技术原理。专业开发者需要对这些技术细节有直观的把握,既能具体到在源代码层面描述,又能通用到适应不同场景。这正是模式的价值所在。本书介绍的模式旨在帮助从业者深入理解各种产品和服务的内在机制,以便做出明智且有效的决策。

本书的主要读者将是这些专业人士。除了那些需要与现有的分布式系统打交道的人员,还有一部分读者可能需要构建自己的分布式系统。我期望本书中的模式能够为这些读者提供一些有价值的参考,并帮助他们领先一步。书中引用了许多不同产品的设计方案,这些信息对读者来说同样有益。

关于代码示例的说明

本书中大多数模式都提供了代码示例。这些代码示例建立在我研究这些模式时,对各种产品所做的微型实现基础之上。选择编程语言的依据是它的普及度和可读性—Java便是一个优秀的选择。示例中只用到了Java最基本的语言特性,即方法和类,这在大多数编程语言中都是通用的。即便是只熟悉其他编程语言的读者,也应该能够轻松地理解这些代码示例。不过,需要明确的是,本书并非专为某个具体的软件平台编写。一旦掌握了这些代码示例,你会发现无论是C++、Rust、Go、Scala还是Zig,其代码库中都有这些模式的影子。我期望的是,通过熟悉这些代码示例和模式,你将能更加轻松地阅读和理解各种开源产品的源代码。

阅读指南

本书共分为六部分。首先是两章叙述性章节,这些章节构成了第一部分,它们涵盖了分布式系统设计的基本主题,介绍了分布式系统设计中的挑战及其解决策略,但并未深入讨论这些策略的细节。

第二部分至第六部分提供了按模式结构化的详尽解决方案。这些模式被划分为四个核心类别:复制、分区、集群管理和网络通信。每一类都是构建分布式系统的关键要素。

请将这些模式当作一种参考手册,不需要逐字逐句地阅读。你可以先浏览叙述性章节,以获得对本书内容的整体理解,再根据个人兴趣和实际需求,深入研究各个模式。

我希望这些模式能够协助同行软件专业人员在工作中做出明智的决策。


目录

译者序

推荐序

前言

致谢

第一部分 概述

第1章 分布式系统 2

1.1 单服务器的限制 3

1.2 业务逻辑和数据层分离 4

1.3 数据分区 4

1.4 故障观察 5

1.5 复制:屏蔽故障 6

1.5.1 进程终止甚至崩溃 6

1.5.2 网络延迟 6

1.5.3 进程暂停 6

1.5.4 时钟不同步 7

1.6 定义分布式系统 7

1.7 模式方法 7

第2章 模式概述 9

2.1 在单服务器上保持数据的弹性 10

2.2 竞争性更新 11

2.3 处理主节点失效 12

2.4 依托“世代时钟”解决多节点故障问题 14

2.5 符合仲裁机制方可提交日志记录 17

2.6 从节点基于高水位标记提交 19

2.7 主节点用消息队列来保持对众多客户端的响应 23

2.8 由从节点处理读请求以减轻主节点的负担 29

2.9 把大量数据分散到多节点分区 30

2.10 通过复制分区提高集群弹性 32

2.11 跨分区维持一致性至少需要两个阶段 33

2.12 分布式系统的顺序不能依赖于系统时间戳 35

2.13 一致性核心负责管理数据集群的成员资格 42

2.14 使用Gossip传播机制来管理分布式集群 45

第二部分 数据复制模式

第3章 预写日志 53

3.1 问题的提出 54

3.2 解决方案 54

3.2.1 实现考虑 56

3.2.2 在事务存储中的使用 56

3.2.3 与事件溯源对比 57

3.3 示例 58

第4章 日志分段 59

4.1 问题的提出 60

4.2 解决方案 60

4.3 示例 61

第5章 低水位标记 62

5.1 问题的提出 63

5.2 解决方案 63

5.2.1 基于快照的低水位标记 63

5.2.2 基于时间的低水位标记 64

5.3 示例 65

第6章 主节点与从节点 66

6.1 问题的提出 67

6.2 解决方案 67

6.2.1 主节点选举 67

6.2.2 仅有多数读/写不足以提供强一致性保证 72

6.3 示例 72

第7章 心跳机制 73

7.1 问题的提出 74

7.2 解决方案 74

7.2.1 小型集群:基于共识算法的系统 75

7.2.2 技术考虑 76

7.2.3 大型集群:基于Gossip协议 76

7.3 示例 77

第8章 多数法定节点数 78

8.1 问题的提出 79

8.2 解决方案 79

8.2.1 决定集群中服务器的数量 79

8.2.2 灵活的多数法定节点数 80

8.3 示例 81

第9章 世代时钟 82

9.1 问题的提出 83

9.2 解决方案 83

9.3 示例 86

第10章 高水位标记 87

10.1 问题的提出 88

10.2 解决方案 88

10.3 示例 92

第11章 Paxos 93

11.1 问题的提出 94

11.2 解决方案 94

11.2.1 协议流程 94

11.2.2 键值存储示例 101

11.2.3 弹性Paxos 105

11.3 示例 105

第12章 复制日志 106

12.1 问题的提出 107

12.2 解决方案 107

12.2.1 Multi-Paxos和Raft 107

12.2.2 复制客户端请求 108

12.2.3 主节点选举 113

12.2.4 技术考虑 118

12.2.5 推送与拉取 120

12.2.6 日志中有什么 120

12.3 示例 125

第13章 单一更新队列 126

13.1 问题的提出 127

13.2 解决方案 127

13.2.1 队列的选择 130

13.2.2 使用通道和轻量级线程 131

13.2.3 限流 131

13.2.4 其他考虑 132

13.3 示例 132

第14章 请求等待列表 133

14.1 问题的提出 134

14.2 解决方案 134

14.3 示例 139

第15章 幂等接收器 140

15.1 问题的提出 141

15.2 解决方案 141

15.2.1 使已保存的客户端请求过期 144

15.2.2 移除已注册的客户端 145

15.2.3 最多一次、至少一次和恰好一次操作 145

15.3 示例 146

第16章 由从节点处理读请求 147

16.1 问题的提出 148

16.2 解决方案 148

16.2.1 寻找最近的副本 148

16.2.2 连接断开或慢速从节点 151

16.2.3 读写一致性 151

16.2.4 线性化读 154

16.3 示例 154

第17章 版本化值 155

17.1 问题的提出 156

17.2 解决方案 156

17.2.1 版本化键的排序 156

17.2.2 读多个版本 159

17.2.3 MVCC和事务隔离性 160

17.2.4 使用类似RocksDB的存储引擎 161

17.3 示例 162

第18章 版本向量 163

18.1 问题的提出 164

18.2 解决方案 164

18.2.1 版本向量比较 165

18.2.2 在键值存储中使用版本向量 167

18.3 示例 174

第三部分 数据分区模式

第19章 固定分区 177

19.1 问题的提出 178

19.2 解决方案 178

19.2.1 选择哈希函数 179

19.2.2 将分区映射到集群节点 179

19.2.3 替代方案:分区数量与节点数量成比例 190

19.3 示例 195

第20章 键范围分区 196

20.1 问题的提出 197

20.2 解决方案 197

20.2.1 预定义键范围 197

20.2.2 示例场景 200

20.2.3 自动分割范围 201

20.3 示例 206

第21章 两阶段提交 207

21.1 问题的提出 208

21.2 解决方案 208

21.2.1 锁和事务隔离性 210

21.2.2 提交和回滚  216

21.2.3 示例场景 220

21.2.4 使用版本化值 225

21.2.5 使用复制日志 234

21.2.6 故障处理 234

21.2.7 异构系统中的事务 238

21.3 示例 239

第四部分 分布式时间的模式

第22章 Lamport时钟 243

22.1 问题的提出 244

22.2 解决方案 244

22.2.1 因果关系、时间和先后关系 245

22.2.2 键值存储示例 245

22.2.3 部分有序 247

22.2.4 单个主节点更新值 247

22.3 示例 248

第23章 混合时钟 249

23.1 问题的提出 250

23.2 解决方案 250

23.2.1 使用混合时钟的多版本存储 252

23.2.2 使用时间戳读取值 254

23.2.3 为分布式事务分配时间戳 254

23.3 示例 256

第24章 时钟约束等待 257

24.1 问题的提出 258

24.2 解决方案 259

24.2.1 读请求重启 261

24.2.2 使用时钟约束API 263

24.3 示例 268

第五部分 集群管理模式

第25章 一致性核心 271

25.1 问题的提出 272

25.2 解决方案 272

25.2.1 元数据存储 273

25.2.2 处理客户端交互 274

25.3 示例 276

第26章 租约 277

26.1 问题的提出 278

26.2 解决方案 278

26.2.1 将租约附加到键值存储中的键上 282

26.2.2 处理主节点失效 284

26.3 示例 285

第27章 状态监控 286

27.1 问题的提出 287

27.2 解决方案 287

27.2.1 客户端实现 287

27.2.2 服务器端实现 288

27.2.3 处理连接失败 290

27.3 示例 292

第28章 Gossip传播 293

28.1 问题的提出 294

28.2 解决方案 294

28.2.1 避免不必要的状态交换 298

28.2.2 选择Gossip节点的标准 300

28.2.3 群组成员资格和故障检测 300

28.2.4 处理节点重启 301

28.3 示例 301

第29章 应急主节点 302

29.1 问题的提出 303

29.2 解决方案 303

29.2.1 向所有现有成员发送成员资格更新 306

29.2.2 示例场景 308

29.2.3 处理缺失的成员资格更新 310

29.2.4 故障检测 311

29.2.5 与主从模式的比较 316

29.3 示例 316

第六部分 节点间通信模式

第30章 单套接字通道 319

30.1 问题的提出 320

30.2 解决方案 320

30.3 示例 322

第31章 请求批处理 323

31.1 问题的提出 324

31.2 解决方案 324

31.3 示例 328

第32章 请求管道 329

32.1 问题的提出 330

32.2 解决方案 330

32.3 示例 332

参考文献 333


短评

    产品特色