分布式.md 17.6 KB
Newer Older
C
CyC2018 已提交
1
# 一、分布式锁
C
CyC2018 已提交
2

C
CyC2018 已提交
3
在单机场景下,可以使用语言的内置锁来实现进程同步。但是在分布式场景下,需要同步的进程可能位于不同的节点上,那么就需要使用分布式锁。
C
CyC2018 已提交
4

C
CyC2018 已提交
5
阻塞锁通常使用互斥量来实现:
C
CyC2018 已提交
6

C
CyC2018 已提交
7 8
- 互斥量为 0 表示有其它进程在使用锁,此时处于锁定状态;
- 互斥量为 1 表示未锁定状态。
C
CyC2018 已提交
9

C
CyC2018 已提交
10
1 和 0 可以用一个整型值表示,也可以用某个数据是否存在表示。
C
CyC2018 已提交
11

C
CyC2018 已提交
12
## 数据库的唯一索引
C
CyC2018 已提交
13

C
CyC2018 已提交
14
获得锁时向表中插入一条记录,释放锁时删除这条记录。唯一索引可以保证该记录只被插入一次,那么就可以用这个记录是否存在来判断是否存于锁定状态。
C
CyC2018 已提交
15

C
CyC2018 已提交
16
存在以下几个问题:
C
CyC2018 已提交
17

C
CyC2018 已提交
18 19 20
- 锁没有失效时间,解锁失败的话其它进程无法再获得该锁。
- 只能是非阻塞锁,插入失败直接就报错了,无法重试。
- 不可重入,已经获得锁的进程也必须重新获取锁。
C
CyC2018 已提交
21

C
CyC2018 已提交
22
## Redis 的 SETNX 指令
C
CyC2018 已提交
23

C
CyC2018 已提交
24
使用 SETNX(set if not exist)指令插入一个键值对,如果 Key 已经存在,那么会返回 False,否则插入成功并返回 True。
C
CyC2018 已提交
25

C
CyC2018 已提交
26
SETNX 指令和数据库的唯一索引类似,保证了只存在一个 Key 的键值对,那么可以用一个 Key 的键值对是否存在来判断是否存于锁定状态。
C
CyC2018 已提交
27

C
CyC2018 已提交
28
EXPIRE 指令可以为一个键值对设置一个过期时间,从而避免了数据库唯一索引实现方式中释放锁失败的问题。
C
CyC2018 已提交
29

C
CyC2018 已提交
30
## Redis 的 RedLock 算法
C
CyC2018 已提交
31

C
CyC2018 已提交
32
使用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时仍然可用。
C
CyC2018 已提交
33

C
CyC2018 已提交
34 35 36
- 尝试从 N 个相互独立 Redis 实例获取锁;
- 计算获取锁消耗的时间,只有当这个时间小于锁的过期时间,并且从大多数(N / 2 + 1)实例上获取了锁,那么就认为锁获取成功了;
- 如果锁获取失败,就到每个实例上释放锁。
C
CyC2018 已提交
37

C
CyC2018 已提交
38
## Zookeeper 的有序节点
C
CyC2018 已提交
39

C
CyC2018 已提交
40
### 1. Zookeeper 抽象模型
C
CyC2018 已提交
41

C
CyC2018 已提交
42
Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父节点为 /app1。
C
CyC2018 已提交
43

C
CyC2018 已提交
44
<img src="index_files/b3a421e3-41b4-4e99-b612-bc695a7f622f.jpg" width="400px">
C
CyC2018 已提交
45

C
CyC2018 已提交
46
### 2. 节点类型
C
CyC2018 已提交
47

C
CyC2018 已提交
48 49 50
- 永久节点:不会因为会话结束或者超时而消失;
- 临时节点:如果会话结束或者超时就会消失;
- 有序节点:会在节点名的后面加一个数字后缀,并且是有序的,例如生成的有序节点为 /lock/node-0000000000,它的下一个有序节点则为 /lock/node-0000000001,以此类推。
C
CyC2018 已提交
51

C
CyC2018 已提交
52
### 3. 监听器
C
CyC2018 已提交
53

C
CyC2018 已提交
54
为一个节点注册监听器,在节点状态发生改变时,会给客户端发送消息。
C
CyC2018 已提交
55

C
CyC2018 已提交
56
### 4. 分布式锁实现
C
CyC2018 已提交
57

C
CyC2018 已提交
58 59 60 61
- 创建一个锁目录 /lock;
- 当一个客户端需要获取锁时,在 /lock 下创建临时的且有序的子节点;
-  客户端获取 /lock 下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁;否则监听自己的前一个子节点,获得子节点的变更通知后重复此步骤直至获得锁;
- 执行业务代码,完成后,删除对应的子节点。
C
CyC2018 已提交
62

C
CyC2018 已提交
63
### 5. 会话超时
C
CyC2018 已提交
64

C
CyC2018 已提交
65
如果一个已经获得锁的会话超时了,因为创建的是临时节点,所以该会话对应的临时节点会被删除,其它会话就可以获得锁了。可以看到,Zookeeper 分布式锁不会出现数据库的唯一索引实现的分布式锁释放锁失败问题。
C
CyC2018 已提交
66

C
CyC2018 已提交
67
### 6. 羊群效应
C
CyC2018 已提交
68

C
CyC2018 已提交
69
一个节点未获得锁,只需要监听自己的前一个子节点,这是因为如果监听所有的子节点,那么任意一个子节点状态改变,其它所有子节点都会收到通知(羊群效应),而我们只希望它的后一个子节点收到通知。
C
CyC2018 已提交
70

C
CyC2018 已提交
71
# 二、分布式事务
C
CyC2018 已提交
72

C
CyC2018 已提交
73
指事务的操作位于不同的节点上,需要保证事务的 ACID 特性。
C
CyC2018 已提交
74

C
CyC2018 已提交
75
例如在下单场景下,库存和订单如果不在同一个节点上,就涉及分布式事务。
C
CyC2018 已提交
76

C
CyC2018 已提交
77
## 本地消息表
C
CyC2018 已提交
78

C
CyC2018 已提交
79
本地消息表与业务数据表处于同一个数据库中,这样就能利用本地事务来保证在对这两个表的操作满足事务特性,并且使用了消息队列来保证最终一致性。
C
CyC2018 已提交
80

C
CyC2018 已提交
81 82 83
1. 在分布式事务操作的一方完成写业务数据的操作之后向本地消息表发送一个消息,本地事务能保证这个消息一定会被写入本地消息表中。
2. 之后将本地消息表中的消息转发到 Kafka 等消息队列中,如果转发成功则将消息从本地消息表中删除,否则继续重新转发。
3. 在分布式事务操作的另一方从消息队列中读取一个消息,并执行消息中的操作。
C
CyC2018 已提交
84

C
CyC2018 已提交
85
![](index_files/76c7597a-8316-460d-b8fb-9752c4c43947.jpg)
C
CyC2018 已提交
86

C
CyC2018 已提交
87
## 2PC
C
CyC2018 已提交
88

C
CyC2018 已提交
89
两阶段提交(Two-phase Commit,2PC),通过引入协调者(Coordinator)来协调参与者的行为,并最终决定这些参与者是否要真正执行事务。
C
CyC2018 已提交
90

C
CyC2018 已提交
91
### 1. 运行过程
C
CyC2018 已提交
92

C
CyC2018 已提交
93
#### 1.1 准备阶段
C
CyC2018 已提交
94 95 96

协调者询问参与者事务是否执行成功,参与者发回事务执行结果。

C
CyC2018 已提交
97
<img src="index_files/963fac12-4eac-4922-8a5f-f262c11f80fb.jpg" width="700px">
C
CyC2018 已提交
98

C
CyC2018 已提交
99
#### 1.2 提交阶段
C
CyC2018 已提交
100 101 102 103 104

如果事务在每个参与者上都执行成功,事务协调者发送通知让参与者提交事务;否则,协调者发送通知让参与者回滚事务。

需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。

C
CyC2018 已提交
105
<img src="index_files/9ffb82ad-9b7f-44df-b93f-fc8b3f4093a6.jpg" width="700px">
C
CyC2018 已提交
106

C
CyC2018 已提交
107
### 2. 存在的问题
C
CyC2018 已提交
108

C
CyC2018 已提交
109
#### 2.1 同步阻塞
C
CyC2018 已提交
110 111 112

所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。

C
CyC2018 已提交
113
#### 2.2 单点问题
C
CyC2018 已提交
114

C
CyC2018 已提交
115
协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待,无法完成其它操作。
C
CyC2018 已提交
116

C
CyC2018 已提交
117
#### 2.3 数据不一致
C
CyC2018 已提交
118

C
CyC2018 已提交
119
在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。
C
CyC2018 已提交
120

C
CyC2018 已提交
121
#### 2.4 太过保守
C
CyC2018 已提交
122 123 124

任意一个节点失败就会导致整个事务失败,没有完善的容错机制。

C
CyC2018 已提交
125
# 三、CAP
C
CyC2018 已提交
126

C
CyC2018 已提交
127
分布式系统不可能同时满足一致性(C:Consistency)、可用性(A:Availability)和分区容忍性(P:Partition Tolerance),最多只能同时满足其中两项。
C
CyC2018 已提交
128

C
CyC2018 已提交
129
<img src="index_files/c6fdb958-578d-4685-a5fa-400857be91d5.jpg" width="500px">
C
CyC2018 已提交
130

C
CyC2018 已提交
131
## 一致性
C
CyC2018 已提交
132

C
CyC2018 已提交
133
一致性指的是多个数据副本是否能保持一致的特性,在一致性的条件下,系统在执行数据更新操作之后能够从一致性状态转移到另一个一致性状态。
C
CyC2018 已提交
134 135 136

对系统的一个数据更新成功之后,如果所有用户都能够读取到最新的值,该系统就被认为具有强一致性。

C
CyC2018 已提交
137
## 可用性
C
CyC2018 已提交
138

C
CyC2018 已提交
139
可用性指分布式系统在面对各种异常时可以提供正常服务的能力,可以用系统可用时间占总时间的比值来衡量,4 个 9 的可用性表示系统 99.99% 的时间是可用的。
C
CyC2018 已提交
140

C
CyC2018 已提交
141
在可用性条件下,要求系统提供的服务一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。
C
CyC2018 已提交
142

C
CyC2018 已提交
143
## 分区容忍性
C
CyC2018 已提交
144 145 146

网络分区指分布式系统中的节点被划分为多个区域,每个区域内部可以通信,但是区域之间无法通信。

C
CyC2018 已提交
147
在分区容忍性条件下,分布式系统在遇到任何网络分区故障的时候,仍然需要能对外提供一致性和可用性的服务,除非是整个网络环境都发生了故障。
C
CyC2018 已提交
148

C
CyC2018 已提交
149
## 权衡
C
CyC2018 已提交
150

C
CyC2018 已提交
151
在分布式系统中,分区容忍性必不可少,因为需要总是假设网络是不可靠的。因此,CAP 理论实际上是要在可用性和一致性之间做权衡。
C
CyC2018 已提交
152

C
CyC2018 已提交
153
可用性和一致性往往是冲突的,很难使它们同时满足。在多个节点之间进行数据同步时,
C
CyC2018 已提交
154

C
CyC2018 已提交
155 156
- 为了保证一致性(CP),不能访问未同步完成的节点,也就失去了部分可用性;
- 为了保证可用性(AP),允许读取所有节点的数据,但是数据可能不一致。
C
CyC2018 已提交
157

C
CyC2018 已提交
158
![](index_files/0b587744-c0a8-46f2-8d72-e8f070d67b4b.jpg)
C
CyC2018 已提交
159

C
CyC2018 已提交
160
# 四、BASE
C
CyC2018 已提交
161

C
CyC2018 已提交
162
BASE 是基本可用(Basically Available)、软状态(Soft State)和最终一致性(Eventually Consistent)三个短语的缩写。
C
CyC2018 已提交
163

C
CyC2018 已提交
164
BASE 理论是对 CAP 中一致性和可用性权衡的结果,它的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
C
CyC2018 已提交
165 166


C
CyC2018 已提交
167
## 基本可用
C
CyC2018 已提交
168 169 170 171 172

指分布式系统在出现故障的时候,保证核心可用,允许损失部分可用性。

例如,电商在做促销时,为了保证购物系统的稳定性,部分消费者可能会被引导到一个降级的页面。

C
CyC2018 已提交
173
## 软状态
C
CyC2018 已提交
174

C
CyC2018 已提交
175
指允许系统中的数据存在中间状态,并认为该中间状态不会影响系统整体可用性,即允许系统不同节点的数据副本之间进行同步的过程存在时延。
C
CyC2018 已提交
176

C
CyC2018 已提交
177
## 最终一致性
C
CyC2018 已提交
178 179 180

最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能达到一致的状态。

C
CyC2018 已提交
181
ACID 要求强一致性,通常运用在传统的数据库系统上。而 BASE 要求最终一致性,通过牺牲强一致性来达到可用性,通常运用在大型分布式系统中。
C
CyC2018 已提交
182

C
CyC2018 已提交
183
在实际的分布式场景中,不同业务单元和组件对一致性的要求是不同的,因此 ACID 和 BASE 往往会结合在一起使用。
C
CyC2018 已提交
184

C
CyC2018 已提交
185
# 五、Paxos
C
CyC2018 已提交
186 187 188 189 190

用于达成共识性问题,即对多个节点产生的值,该算法能保证只选出唯一一个值。

主要有三类节点:

C
CyC2018 已提交
191 192 193
- 提议者(Proposer):提议一个值;
- 接受者(Acceptor):对每个提议进行投票;
- 告知者(Learner):被告知投票的结果,不参与投票过程。
C
CyC2018 已提交
194

C
CyC2018 已提交
195
![](index_files/b988877c-0f0a-4593-916d-de2081320628.jpg)
C
CyC2018 已提交
196

C
CyC2018 已提交
197
## 执行过程
C
CyC2018 已提交
198

C
CyC2018 已提交
199
规定一个提议包含两个字段:[n, v],其中 n 为序号(具有唯一性),v 为提议值。
C
CyC2018 已提交
200

C
CyC2018 已提交
201
### 1. Prepare 阶段
C
CyC2018 已提交
202

C
CyC2018 已提交
203
下图演示了两个 Proposer 和三个 Acceptor 的系统中运行该算法的初始过程,每个 Proposer 都会向所有 Acceptor 发送 Prepare 请求。
C
CyC2018 已提交
204

C
CyC2018 已提交
205
![](index_files/1a9977e4-2f5c-49a6-aec9-f3027c9f46a7.png)
C
CyC2018 已提交
206

C
CyC2018 已提交
207
当 Acceptor 接收到一个 Prepare 请求,包含的提议为 [n1, v1],并且之前还未接收过 Prepare 请求,那么发送一个 Prepare 响应,设置当前接收到的提议为 [n1, v1],并且保证以后不会再接受序号小于 n1 的提议。
C
CyC2018 已提交
208

C
CyC2018 已提交
209
如下图,Acceptor X 在收到 [n=2, v=8] 的 Prepare 请求时,由于之前没有接收过提议,因此就发送一个 [no previous] 的 Prepare 响应,设置当前接收到的提议为 [n=2, v=8],并且保证以后不会再接受序号小于 2 的提议。其它的 Acceptor 类似。
C
CyC2018 已提交
210

C
CyC2018 已提交
211
![](index_files/fb44307f-8e98-4ff7-a918-31dacfa564b4.jpg)
C
CyC2018 已提交
212

C
CyC2018 已提交
213
如果 Acceptor 接收到一个 Prepare 请求,包含的提议为 [n2, v2],并且之前已经接收过提议 [n1, v1]。如果 n1 > n2,那么就丢弃该提议请求;否则,发送 Prepare 响应,该 Prepare 响应包含之前已经接收过的提议 [n1, v1],设置当前接收到的提议为 [n2, v2],并且保证以后不会再接受序号小于 n2 的提议。
C
CyC2018 已提交
214

C
CyC2018 已提交
215
如下图,Acceptor Z 收到 Proposer A 发来的 [n=2, v=8] 的 Prepare 请求,由于之前已经接收过 [n=4, v=5] 的提议,并且 n > 2,因此就抛弃该提议请求;Acceptor X 收到 Proposer B 发来的 [n=4, v=5] 的 Prepare 请求,因为之前接收到的提议为 [n=2, v=8],并且 2 <= 4,因此就发送 [n=2, v=8] 的 Prepare 响应,设置当前接收到的提议为 [n=4, v=5],并且保证以后不会再接受序号小于 4 的提议。Acceptor Y 类似。
C
CyC2018 已提交
216

C
CyC2018 已提交
217
![](index_files/2bcc58ad-bf7f-485c-89b5-e7cafc211ce2.jpg)
C
CyC2018 已提交
218

C
CyC2018 已提交
219
### 2. Accept 阶段
C
CyC2018 已提交
220

C
CyC2018 已提交
221
当一个 Proposer 接收到超过一半 Acceptor 的 Prepare 响应时,就可以发送 Accept 请求。
C
CyC2018 已提交
222

C
CyC2018 已提交
223
Proposer A 接收到两个 Prepare 响应之后,就发送 [n=2, v=8] Accept 请求。该 Accept 请求会被所有 Acceptor 丢弃,因为此时所有 Acceptor 都保证不接受序号小于 4 的提议。
C
CyC2018 已提交
224

C
CyC2018 已提交
225
Proposer B 过后也收到了两个 Prepare 响应,因此也开始发送 Accept 请求。需要注意的是,Accept 请求的 v 需要取它收到的最大提议编号对应的 v 值,也就是 8。因此它发送 [n=4, v=8] 的 Accept 请求。
C
CyC2018 已提交
226

C
CyC2018 已提交
227
![](index_files/9b838aee-0996-44a5-9b0f-3d1e3e2f5100.png)
C
CyC2018 已提交
228

C
CyC2018 已提交
229
### 3. Learn 阶段
C
CyC2018 已提交
230

C
CyC2018 已提交
231
Acceptor 接收到 Accept 请求时,如果序号大于等于该 Acceptor 承诺的最小序号,那么就发送 Learn 提议给所有的 Learner。当 Learner 发现有大多数的 Acceptor 接收了某个提议,那么该提议的提议值就被 Paxos 选择出来。
C
CyC2018 已提交
232

C
CyC2018 已提交
233
![](index_files/bf667594-bb4b-4634-bf9b-0596a45415ba.jpg)
C
CyC2018 已提交
234

C
CyC2018 已提交
235
## 约束条件
C
CyC2018 已提交
236

C
CyC2018 已提交
237
### 1\. 正确性
C
CyC2018 已提交
238 239 240

指只有一个提议值会生效。

C
CyC2018 已提交
241
因为 Paxos 协议要求每个生效的提议被多数 Acceptor 接收,并且 Acceptor 不会接受两个不同的提议,因此可以保证正确性。
C
CyC2018 已提交
242

C
CyC2018 已提交
243
### 2\. 可终止性
C
CyC2018 已提交
244 245 246

指最后总会有一个提议生效。

C
CyC2018 已提交
247
Paxos 协议能够让 Proposer 发送的提议朝着能被大多数 Acceptor 接受的那个提议靠拢,因此能够保证可终止性。
C
CyC2018 已提交
248

C
CyC2018 已提交
249
# 六、Raft
C
CyC2018 已提交
250

C
CyC2018 已提交
251
Raft 也是分布式一致性协议,主要是用来竞选主节点。
C
CyC2018 已提交
252

C
CyC2018 已提交
253
## 单个 Candidate 的竞选
C
CyC2018 已提交
254

C
CyC2018 已提交
255
有三种节点:Follower、Candidate 和 Leader。Leader 会周期性的发送心跳包给 Follower。每个 Follower 都设置了一个随机的竞选超时时间,一般为 150ms~300ms,如果在这个时间内没有收到 Leader 的心跳包,就会变成 Candidate,进入竞选阶段。
C
CyC2018 已提交
256

C
CyC2018 已提交
257
- 下图展示一个分布式系统的最初阶段,此时只有 Follower 没有 Leader。Node A 等待一个随机的竞选超时时间之后,没收到 Leader 发来的心跳包,因此进入竞选阶段。
C
CyC2018 已提交
258

C
CyC2018 已提交
259
![](index_files/111521118015898.gif)
C
CyC2018 已提交
260

C
CyC2018 已提交
261
- 此时 Node A 发送投票请求给其它所有节点。
C
CyC2018 已提交
262

C
CyC2018 已提交
263
![](index_files/111521118445538.gif)
C
CyC2018 已提交
264

C
CyC2018 已提交
265
- 其它节点会对请求进行回复,如果超过一半的节点回复了,那么该 Candidate 就会变成 Leader。
C
CyC2018 已提交
266

C
CyC2018 已提交
267
![](index_files/111521118483039.gif)
C
CyC2018 已提交
268

C
CyC2018 已提交
269
- 之后 Leader 会周期性地发送心跳包给 Follower,Follower 接收到心跳包,会重新开始计时。
C
CyC2018 已提交
270

C
CyC2018 已提交
271
![](index_files/111521118640738.gif)
C
CyC2018 已提交
272

C
CyC2018 已提交
273
## 多个 Candidate 竞选
C
CyC2018 已提交
274

C
CyC2018 已提交
275
- 如果有多个 Follower 成为 Candidate,并且所获得票数相同,那么就需要重新开始投票。例如下图中 Node B 和 Node D 都获得两票,需要重新开始投票。
C
CyC2018 已提交
276

C
CyC2018 已提交
277
![](index_files/111521119203347.gif)
C
CyC2018 已提交
278

C
CyC2018 已提交
279
- 由于每个节点设置的随机竞选超时时间不同,因此下一次再次出现多个 Candidate 并获得同样票数的概率很低。
C
CyC2018 已提交
280

C
CyC2018 已提交
281
![](index_files/111521119368714.gif)
C
CyC2018 已提交
282

C
CyC2018 已提交
283
## 数据同步
C
CyC2018 已提交
284

C
CyC2018 已提交
285
- 来自客户端的修改都会被传入 Leader。注意该修改还未被提交,只是写入日志中。
C
CyC2018 已提交
286

C
CyC2018 已提交
287
![](index_files/71550414107576.gif)
C
CyC2018 已提交
288

C
CyC2018 已提交
289
- Leader 会把修改复制到所有 Follower。
C
CyC2018 已提交
290

C
CyC2018 已提交
291
![](index_files/91550414131331.gif)
C
CyC2018 已提交
292

C
CyC2018 已提交
293
- Leader 会等待大多数的 Follower 也进行了修改,然后才将修改提交。
C
CyC2018 已提交
294

C
CyC2018 已提交
295
![](index_files/101550414151983.gif)
C
CyC2018 已提交
296

C
CyC2018 已提交
297
- 此时 Leader 会通知的所有 Follower 让它们也提交修改,此时所有节点的值达成一致。
C
CyC2018 已提交
298

C
CyC2018 已提交
299
![](index_files/111550414182638.gif)
C
CyC2018 已提交
300

C
CyC2018 已提交
301
# 参考
C
CyC2018 已提交
302

C
CyC2018 已提交
303 304 305 306 307 308 309 310 311 312 313
- 倪超. 从 Paxos 到 ZooKeeper : 分布式一致性原理与实践 [M]. 电子工业出版社, 2015.
[Distributed locks with Redis](https://redis.io/topics/distlock)
[浅谈分布式锁](http://www.linkedkeeper.com/detail/blog.action?bid=1023)
[基于 Zookeeper 的分布式锁](http://www.dengshenyu.com/java/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/2017/10/23/zookeeper-distributed-lock.html)
[Raft: Understandable Distributed Consensus](http://thesecretlivesofdata.com/raft)
[聊聊分布式事务,再说说解决方案](https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html)
[分布式系统的事务处理](https://coolshell.cn/articles/10910.html)
[深入理解分布式事务](https://juejin.im/entry/577c6f220a2b5800573492be)
[What is CAP theorem in distributed database system?](http://www.colooshiki.com/index.php/2017/04/20/what-is-cap-theorem-in-distributed-database-system/)
[NEAT ALGORITHMS - PAXOS](http://harry.me/blog/2014/12/27/neat-algorithms-paxos/)
[Paxos By Example](https://angus.nyc/2012/paxos-by-example/)
C
CyC2018 已提交
314

C
CyC2018 已提交
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
---bottom---CyC---
![](index_files/b3a421e3-41b4-4e99-b612-bc695a7f622f.jpg)
![](index_files/76c7597a-8316-460d-b8fb-9752c4c43947.jpg)
![](index_files/963fac12-4eac-4922-8a5f-f262c11f80fb.jpg)
![](index_files/9ffb82ad-9b7f-44df-b93f-fc8b3f4093a6.jpg)
![](index_files/c6fdb958-578d-4685-a5fa-400857be91d5.jpg)
![](index_files/0b587744-c0a8-46f2-8d72-e8f070d67b4b.jpg)
![](index_files/b988877c-0f0a-4593-916d-de2081320628.jpg)
![](index_files/1a9977e4-2f5c-49a6-aec9-f3027c9f46a7.png)
![](index_files/fb44307f-8e98-4ff7-a918-31dacfa564b4.jpg)
![](index_files/2bcc58ad-bf7f-485c-89b5-e7cafc211ce2.jpg)
![](index_files/9b838aee-0996-44a5-9b0f-3d1e3e2f5100.png)
![](index_files/bf667594-bb4b-4634-bf9b-0596a45415ba.jpg)
![](index_files/111521118015898.gif)
![](index_files/111521118445538.gif)
![](index_files/111521118483039.gif)
![](index_files/111521118640738.gif)
![](index_files/111521119203347.gif)
![](index_files/111521119368714.gif)
![](index_files/71550414107576.gif)
![](index_files/91550414131331.gif)
![](index_files/101550414151983.gif)
![](index_files/111550414182638.gif)