|
2 | 2 |
|
3 | 3 | > [FrancisQ](https://juejin.im/user/5c33853851882525ea106810) 投稿。
|
4 | 4 |
|
5 |
| -## 1. 好久不见 |
6 |
| - |
7 |
| -离上一篇文章的发布也快一个月了,想想已经快一个月没写东西了,其中可能有期末考试、课程设计和驾照考试,但这都不是借口! |
8 |
| - |
9 |
| -一到冬天就懒的不行,望广大掘友督促我🙄🙄✍️✍️。 |
10 |
| - |
11 |
| -> 文章很长,先赞后看,养成习惯。❤️ 🧡 💛 💚 💙 💜 |
12 |
| -
|
13 |
| -## 2. 什么是ZooKeeper |
| 5 | +## 什么是ZooKeeper |
14 | 6 |
|
15 | 7 | `ZooKeeper` 由 `Yahoo` 开发,后来捐赠给了 `Apache` ,现已成为 `Apache` 顶级项目。`ZooKeeper` 是一个开源的分布式应用程序协调服务器,其为分布式系统提供一致性服务。其一致性是通过基于 `Paxos` 算法的 `ZAB` 协议完成的。其主要功能包括:配置维护、分布式同步、集群管理、分布式事务等。
|
16 | 8 |
|
|
34 | 26 |
|
35 | 27 | 比如各个分布式组件如何协调起来,如何减少各个系统之间的耦合度,分布式事务的处理,如何去配置整个分布式系统等等。`ZooKeeper` 主要就是解决这些问题的。
|
36 | 28 |
|
37 |
| -## 3. 一致性问题 |
| 29 | +## 一致性问题 |
38 | 30 |
|
39 | 31 | 设计一个分布式系统必定会遇到一个问题—— **因为分区容忍性(partition tolerance)的存在,就必定要求我们需要在系统可用性(availability)和数据一致性(consistency)中做出权衡** 。这就是著名的 `CAP` 定理。
|
40 | 32 |
|
|
44 | 36 |
|
45 | 37 | 而上述前者就是 `Eureka` 的处理方式,它保证了AP(可用性),后者就是我们今天所要讲的 `ZooKeeper` 的处理方式,它保证了CP(数据一致性)。
|
46 | 38 |
|
47 |
| -## 4. 一致性协议和算法 |
| 39 | +## 一致性协议和算法 |
48 | 40 |
|
49 | 41 | 而为了解决数据一致性问题,在科学家和程序员的不断探索中,就出现了很多的一致性协议和算法。比如 2PC(两阶段提交),3PC(三阶段提交),Paxos算法等等。
|
50 | 42 |
|
|
56 | 48 |
|
57 | 49 | 而为什么要去解决数据一致性的问题?你想想,如果一个秒杀系统将服务拆分成了下订单和加积分服务,这两个服务部署在不同的机器上了,万一在消息的传播过程中积分系统宕机了,总不能你这边下了订单却没加积分吧?你总得保证两边的数据需要一致吧?
|
58 | 50 |
|
59 |
| -### 4.1. 2PC(两阶段提交) |
| 51 | +### 2PC(两阶段提交) |
60 | 52 |
|
61 | 53 | 两阶段提交是一种保证分布式系统数据一致性的协议,现在很多数据库都是采用的两阶段提交协议来完成 **分布式事务** 的处理。
|
62 | 54 |
|
|
86 | 78 | * **阻塞问题**,即当协调者发送 `prepare` 请求,参与者收到之后如果能处理那么它将会进行事务的处理但并不提交,这个时候会一直占用着资源不释放,如果此时协调者挂了,那么这些资源都不会再释放了,这会极大影响性能。
|
87 | 79 | * **数据不一致问题**,比如当第二阶段,协调者只发送了一部分的 `commit` 请求就挂了,那么也就意味着,收到消息的参与者会进行事务的提交,而后面没收到的则不会进行事务提交,那么这时候就会产生数据不一致性问题。
|
88 | 80 |
|
89 |
| -### 4.2. 3PC(三阶段提交) |
| 81 | +### 3PC(三阶段提交) |
90 | 82 |
|
91 | 83 | 因为2PC存在的一系列问题,比如单点,容错机制缺陷等等,从而产生了 **3PC(三阶段提交)** 。那么这三阶段又分别是什么呢?
|
92 | 84 |
|
|
104 | 96 |
|
105 | 97 | 所以,要解决一致性问题还需要靠 `Paxos` 算法⭐️ ⭐️ ⭐️ 。
|
106 | 98 |
|
107 |
| -### 4.3. `Paxos` 算法 |
| 99 | +### `Paxos` 算法 |
108 | 100 |
|
109 | 101 | `Paxos` 算法是基于**消息传递且具有高度容错特性的一致性算法**,是目前公认的解决分布式一致性问题最有效的算法之一,**其解决的问题就是在分布式系统中如何就某个值(决议)达成一致** 。
|
110 | 102 |
|
111 | 103 | 在 `Paxos` 中主要有三个角色,分别为 `Proposer提案者`、`Acceptor表决者`、`Learner学习者`。`Paxos` 算法和 `2PC` 一样,也有两个阶段,分别为 `Prepare` 和 `accept` 阶段。
|
112 | 104 |
|
113 |
| -#### 4.3.1. prepare 阶段 |
| 105 | +#### prepare 阶段 |
114 | 106 |
|
115 | 107 | * `Proposer提案者`:负责提出 `proposal`,每个提案者在提出提案时都会首先获取到一个 **具有全局唯一性的、递增的提案编号N**,即在整个集群中是唯一的编号 N,然后将该编号赋予其要提出的提案,在**第一阶段是只将提案编号发送给所有的表决者**。
|
116 | 108 | * `Acceptor表决者`:每个表决者在 `accept` 某提案后,会将该提案编号N记录在本地,这样每个表决者中保存的已经被 accept 的提案中会存在一个**编号最大的提案**,其编号假设为 `maxN`。每个表决者仅会 `accept` 编号大于自己本地 `maxN` 的提案,在批准提案时表决者会将以前接受过的最大编号的提案作为响应反馈给 `Proposer` 。
|
|
119 | 111 |
|
120 | 112 | 
|
121 | 113 |
|
122 |
| -#### 4.3.2. accept 阶段 |
| 114 | +#### accept 阶段 |
123 | 115 |
|
124 | 116 | 当一个提案被 `Proposer` 提出后,如果 `Proposer` 收到了超过半数的 `Acceptor` 的批准(`Proposer` 本身同意),那么此时 `Proposer` 会给所有的 `Acceptor` 发送真正的提案(你可以理解为第一阶段为试探),这个时候 `Proposer` 就会发送提案的内容和提案编号。
|
125 | 117 |
|
|
135 | 127 |
|
136 | 128 | > 对于 `Learner` 来说如何去学习 `Acceptor` 批准的提案内容,这有很多方式,读者可以自己去了解一下,这里不做过多解释。
|
137 | 129 |
|
138 |
| -#### 4.3.3. `paxos` 算法的死循环问题 |
| 130 | +#### paxos 算法的死循环问题 |
139 | 131 |
|
140 | 132 | 其实就有点类似于两个人吵架,小明说我是对的,小红说我才是对的,两个人据理力争的谁也不让谁🤬🤬。
|
141 | 133 |
|
|
147 | 139 |
|
148 | 140 | 那么如何解决呢?很简单,人多了容易吵架,我现在 **就允许一个能提案** 就行了。
|
149 | 141 |
|
150 |
| -## 5. 引出 `ZAB` |
| 142 | +## 引出 `ZAB` |
151 | 143 |
|
152 |
| -### 5.1. `Zookeeper` 架构 |
| 144 | +### Zookeeper 架构 |
153 | 145 |
|
154 | 146 | 作为一个优秀高效且可靠的分布式协调框架,`ZooKeeper` 在解决分布式数据一致性问题时并没有直接使用 `Paxos` ,而是专门定制了一致性协议叫做 `ZAB(ZooKeeper Atomic Broadcast)` 原子广播协议,该协议能够很好地支持 **崩溃恢复** 。
|
155 | 147 |
|
156 | 148 | 
|
157 | 149 |
|
158 |
| -### 5.2. `ZAB` 中的三个角色 |
| 150 | +### ZAB 中的三个角色 |
159 | 151 |
|
160 | 152 | 和介绍 `Paxos` 一样,在介绍 `ZAB` 协议之前,我们首先来了解一下在 `ZAB` 中三个主要的角色,`Leader 领导者`、`Follower跟随者`、`Observer观察者` 。
|
161 | 153 |
|
|
165 | 157 |
|
166 | 158 | 在 `ZAB` 协议中对 `zkServer`(即上面我们说的三个角色的总称) 还有两种模式的定义,分别是 **消息广播** 和 **崩溃恢复** 。
|
167 | 159 |
|
168 |
| -### 5.3. 消息广播模式 |
| 160 | +### 消息广播模式 |
169 | 161 |
|
170 | 162 | 说白了就是 `ZAB` 协议是如何处理写请求的,上面我们不是说只有 `Leader` 能处理写请求嘛?那么我们的 `Follower` 和 `Observer` 是不是也需要 **同步更新数据** 呢?总不能数据只在 `Leader` 中更新了,其他角色都没有得到更新吧?
|
171 | 163 |
|
|
185 | 177 |
|
186 | 178 | 定义这个的原因也是为了顺序性,每个 `proposal` 在 `Leader` 中生成后需要 **通过其 `ZXID` 来进行排序** ,才能得到处理。
|
187 | 179 |
|
188 |
| -### 5.4. 崩溃恢复模式 |
| 180 | +### 崩溃恢复模式 |
189 | 181 |
|
190 | 182 | 说到崩溃恢复我们首先要提到 `ZAB` 中的 `Leader` 选举算法,当系统出现崩溃影响最大应该是 `Leader` 的崩溃,因为我们只有一个 `Leader` ,所以当 `Leader` 出现问题的时候我们势必需要重新选举 `Leader` 。
|
191 | 183 |
|
|
229 | 221 |
|
230 | 222 | 
|
231 | 223 |
|
232 |
| -## 6. Zookeeper的几个理论知识 |
| 224 | +## Zookeeper的几个理论知识 |
233 | 225 |
|
234 | 226 | 了解了 `ZAB` 协议还不够,它仅仅是 `Zookeeper` 内部实现的一种方式,而我们如何通过 `Zookeeper` 去做一些典型的应用场景呢?比如说集群管理,分布式锁,`Master` 选举等等。
|
235 | 227 |
|
236 | 228 | 这就涉及到如何使用 `Zookeeper` 了,但在使用之前我们还需要掌握几个概念。比如 `Zookeeper` 的 **数据模型** 、**会话机制**、**ACL**、**Watcher机制** 等等。
|
237 | 229 |
|
238 |
| -### 6.1. 数据模型 |
| 230 | +### 数据模型 |
239 | 231 |
|
240 | 232 | `zookeeper` 数据存储结构与标准的 `Unix` 文件系统非常相似,都是在根节点下挂很多子节点(树型)。但是 `zookeeper` 中没有文件系统中目录与文件的概念,而是 **使用了 `znode` 作为数据节点** 。`znode` 是 `zookeeper` 中的最小数据单元,每个 `znode` 上都可以保存数据,同时还可以挂载子节点,形成一个树形化命名空间。
|
241 | 233 |
|
|
264 | 256 | * `numChildre`:该节点的子节点个数,如果为临时节点为0。
|
265 | 257 | * `pzxid`:该节点子节点列表最后一次被修改时的事务ID,注意是子节点的 **列表** ,不是内容。
|
266 | 258 |
|
267 |
| -### 6.2. 会话 |
| 259 | +### 会话 |
268 | 260 |
|
269 | 261 | 我想这个对于后端开发的朋友肯定不陌生,不就是 `session` 吗?只不过 `zk` 客户端和服务端是通过 **`TCP` 长连接** 维持的会话机制,其实对于会话来说你可以理解为 **保持连接状态** 。
|
270 | 262 |
|
271 | 263 | 在 `zookeeper` 中,会话还有对应的事件,比如 `CONNECTION_LOSS 连接丢失事件` 、`SESSION_MOVED 会话转移事件` 、`SESSION_EXPIRED 会话超时失效事件` 。
|
272 | 264 |
|
273 |
| -### 6.3. ACL |
| 265 | +### ACL |
274 | 266 |
|
275 | 267 | `ACL` 为 `Access Control Lists` ,它是一种权限控制。在 `zookeeper` 中定义了5种权限,它们分别为:
|
276 | 268 |
|
|
280 | 272 | * `DELETE`:删除子节点的权限。
|
281 | 273 | * `ADMIN`:设置节点 ACL 的权限。
|
282 | 274 |
|
283 |
| -### 6.4. Watcher机制 |
| 275 | +### Watcher机制 |
284 | 276 |
|
285 | 277 | `Watcher` 为事件监听器,是 `zk` 非常重要的一个特性,很多功能都依赖于它,它有点类似于订阅的方式,即客户端向服务端 **注册** 指定的 `watcher` ,当服务端符合了 `watcher` 的某些事件或要求则会 **向客户端发送事件通知** ,客户端收到通知后找到自己定义的 `Watcher` 然后 **执行相应的回调方法** 。
|
286 | 278 |
|
287 | 279 | 
|
288 | 280 |
|
289 |
| -## 7. Zookeeper的几个典型应用场景 |
| 281 | +## Zookeeper的几个典型应用场景 |
290 | 282 |
|
291 | 283 | 前面说了这么多的理论知识,你可能听得一头雾水,这些玩意有啥用?能干啥事?别急,听我慢慢道来。
|
292 | 284 |
|
293 | 285 | 
|
294 | 286 |
|
295 |
| -### 7.1. 选主 |
| 287 | +### 选主 |
296 | 288 |
|
297 | 289 | 还记得上面我们的所说的临时节点吗?因为 `Zookeeper` 的强一致性,能够很好地在保证 **在高并发的情况下保证节点创建的全局唯一性** (即无法重复创建同样的节点)。
|
298 | 290 |
|
|
306 | 298 |
|
307 | 299 | 总的来说,我们可以完全 **利用 临时节点、节点状态 和 `watcher` 来实现选主的功能**,临时节点主要用来选举,节点状态和`watcher` 可以用来判断 `master` 的活性和进行重新选举。
|
308 | 300 |
|
309 |
| -### 7.2. 分布式锁 |
| 301 | +### 分布式锁 |
310 | 302 |
|
311 | 303 | 分布式锁的实现方式有很多种,比如 `Redis` 、数据库 、`zookeeper` 等。个人认为 `zookeeper` 在实现分布式锁这方面是非常非常简单的。
|
312 | 304 |
|
|
330 | 322 |
|
331 | 323 | 具体怎么做呢?其实也很简单,你可以让 **读请求监听比自己小的最后一个写请求节点,写请求只监听比自己小的最后一个节点** ,感兴趣的小伙伴可以自己去研究一下。
|
332 | 324 |
|
333 |
| -### 7.3. 命名服务 |
| 325 | +### 命名服务 |
334 | 326 |
|
335 | 327 | 如何给一个对象设置ID,大家可能都会想到 `UUID`,但是 `UUID` 最大的问题就在于它太长了。。。(太长不一定是好事,嘿嘿嘿)。那么在条件允许的情况下,我们能不能使用 `zookeeper` 来实现呢?
|
336 | 328 |
|
337 | 329 | 我们之前提到过 `zookeeper` 是通过 **树形结构** 来存储数据节点的,那也就是说,对于每个节点的 **全路径**,它必定是唯一的,我们可以使用节点的全路径作为命名方式了。而且更重要的是,路径是我们可以自己定义的,这对于我们对有些有语意的对象的ID设置可以更加便于理解。
|
338 | 330 |
|
339 |
| -### 7.4. 集群管理和注册中心 |
| 331 | +### 集群管理和注册中心 |
340 | 332 |
|
341 | 333 | 看到这里是不是觉得 `zookeeper` 实在是太强大了,它怎么能这么能干!
|
342 | 334 |
|
|
352 | 344 |
|
353 | 345 | 
|
354 | 346 |
|
355 |
| -## 8. 总结 |
356 |
| - |
357 |
| -看到这里的同学实在是太有耐心了👍👍👍,如果觉得我写得不错的话点个赞哈。 |
| 347 | +## 总结 |
358 | 348 |
|
359 |
| -不知道大家是否还记得我讲了什么😒。 |
| 349 | +看到这里的同学实在是太有耐心了👍👍👍不知道大家是否还记得我讲了什么😒。 |
360 | 350 |
|
361 | 351 | 
|
362 | 352 |
|
|
0 commit comments