共计 4795 个字符,预计需要花费 12 分钟才能阅读完成。
概念简述
- 分布式系统协调服务的中间件
- 能够基于 Zookeeper 实现公布 / 订阅、负载平衡、分布式协调 / 告诉、master 选举、分布式锁、分布式队列等
简略说下分布式系统特点
- 多台计算机组成一个整体,一个整体统一对外并且解决同一申请
- 外部的每台计算机都能够相互通信(REST/RPC)
- 客户端到服务端的一次申请到响应完结会经验多台计算机
个性
- 程序一致性:客户端的更新将按发送程序利用
- 原子性:事务要么全副胜利,要么全副失败
- 繁多视图:客户端连贯集群中的任一 Zookeeper 节点,数据都是统一的
- 可靠性:每次对 Zookeeper 的操作状态都会保留在服务端,一旦利用了更新,它将从那时起继续到客户端笼罩更新
- 实时性:客户端能够读取到 Zookeeper 服务端的最新数据
Zookeeper 构造模型
Zookeeper 的数据保留在内存中 。Zookeeper 容许 分布式过程 通过 共享 的层次结构命名空间进行互相协调,层次结构命名空间由 ZooKeeper 中的数据寄存器——Znode 组成,Znode 相似于文件和目录。
- 树型构造,相似 linux 的目录构造或 HTML
- 每个 Zookeeper 节点都有各自的版本号,每当节点数据变动,该节点的版本号会累加
- 每个 Zookeeper 节点存储的数据不宜过大,几 kb 即可
- 节点能够设置权限来限度拜访
ZNode(数据节点)构造
每个 ZNode 由两局部组成:
- stat:状态信息;包含一个数据节点的所有状态信息,包含事务 ID、版本信息和子节点个数等。
- data:数据内容
node 模型,父 node 会有多个子 node
节点类型
- 长久节点
节点创立后就始终存在,直到有删除操作来被动革除这个节点,不会随会话生效而隐没。
- 长期节点
节点生命周期和客户端会话绑定。客户端会话生效 (是会话生效,不是连贯断开) 时,节点隐没。
- 程序节点
不是一种类型,长久和长期节点都会有程序节点,每个 Zookeeper 的父节点会记录子节点的创立先后顺序,在创立的时候主动给子节点的节点名加上一个数字后缀。数字范畴是整型最大值。
watch 机制
针对每个节点的增删改操作,Zookeeper 能够依据 watcher 事件进行监控,当监控的某个 znode 发生变化,就会触发 watch 事件。Zookeeper 的 watch 都是一次性的,触发后立刻销毁。
Zookeeper 的协调机制
其实就是session 工作原理。
- 客户端和服务端连贯会话,每个会话都会设置一个超时工夫
- 客户端和服务端通过心跳机制(客户端向服务端的 ping 包申请) 放弃通信,心跳 session 过期,长期节点则被摈弃
Zookeeper 集群角色
-
leader
- 一个 Zookeeper 集群同一时间只有一个理论工作的 leader,他会保护与 Follower 和 Observer 的心跳
- 执行读和写操作
- 只有 leader 能执行写操作,所有写操作都须要由 leader 将写操作播送给其余服务器
-
follower
- 响应 leader 心跳
- 解决并返回客户端读申请,将客户端写申请转发给 leader 解决
- 在 leader 解决写申请时,参加选举
-
observer
- 响应 leader 心跳
- 解决并返回客户端读申请,放大查问能力
- 不参加选举
要保障 leader 选举快,就要保障 follower 节点可控且尽量少
可靠性
Zookeeper 通过 ZAB 协定保证数据最终一致性。
Paxos 协定
Paxos:https://www.douban.com/note/208430424/(写得好,就懒得再总结了,间接看)
ZAB 协定
Zookeeper 通过 ZAB(Zookeeper Atomic Broadcast 原子播送)这个反对解体复原的一致性协定来保护数据一致性。通过这个协定,Zookeeper 实现了一种主从模式的架构来保障各个正本之间的数据统一。
ZAB 协定次要包含两点:
- 所有写操作必须通过 Leader 实现,Leader 写入本地日志后再复制到所有 Follower,observer 节点
-
一旦 Leader 节点无奈工作,ZAB 会主动从 Follower 节点从新选举出一个 Leader
ZAB 两阶段提交
益处是保障提交过的数据不会失落。因为提交过的数据都是半数通过的,即便 leader 服务器宕机也至多有一半以上的服务器保留有数据。
- follower/observer 节点收到客户端的写申请,将写申请转发给 leader 节点(如果是 leader 节点间接收到写申请则疏忽此步骤)
- leader 节点收到客户端的写申请,先将写申请以 Proposal 的模式发给 follower,期待回复
- follower 收到 proposal 后返回 ACK 给 leader
- leader 收到超过半数的 ACK 回复(leader 节点会默认给本人一个 ACK),则发送 commit 指令给 follower 和 Observer 节点
-
follower/observer 节点收到后处理写申请,再回复 leader 节点
- leader 将处理结果返回客户端
![image-20201111172922556](file://C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20201111172922556.png?lastModify=1605260591)
##### 音讯播送和解体复原
* 音讯播送
过半服务器和 Leader 服务器实现数据状态同步后,就进入音讯播送模式。当一台遵循 ZAB 协定的服务器退出集群,当发现有 Leader 服务器后,就主动进入数据恢复模式,和 Leader 服务器进行数据同步,同步实现后再参加到音讯播送去
Leader 服务器接管到客户端的事务申请,会生成对应事务计划,发动一次音讯播送。当从服务器接管到客户端事务申请,会将申请转发给 Leader 服务器
* 解体复原
当 Leader 服务器出现异常状况,则进入恢复模式,从新选举 Leader 服务器,当过半机器和 Leader 服务器实现数据状态同步之后,就退出恢复模式。服务器在成为 Leader 后,先判断本身未 Commit 的音讯(是否存在于大多数服务器中从而决定是否要将其 Commit
* 小结
* 因为应用主从复制模式,所有写操作都由 Leader 主导,而读操作可通过任意节点实现,因而 Zookeeper 读性能好于写性能,适宜读多写少的场景;* 尽管应用主从,同一时间只有一个 Leader,但 Failover 机制保障了集群不存在单点失败 (SPOF) 的问题;* ZAB 协定保障了 Failover(解体复原)过程中的数据一致性;* 服务器收到数据后先写本地文件再进行解决,保障了数据的持久性
Zookeeper 选举
一些概念
- myid
每个 Zookeeper 服务器的惟一标识。
- zxid
事务 ID,用于标识一次更新操作的 Proposal ID。为了保障 proposal 程序行,zxid 必须枯燥递增。
Zookeeper 应用一个 64 位数来示意,高 32 位是 leader 的 epoch,从 1 开始,每次选出新的 Leader,epoch 加一。低 32 位位该 epoch 内的序号,每次 epoch 变动,都将低 32 位的序号重置。保障了 zxid 的全局递增性。
- 服务器状态
LOOKING、FOLLOWING、LEADING、OBSERVING
-
选票数据结构
- logicClock:每个服务器会保护一个自增整数,示意该服务器发动的第几轮投票
- state:以后服务器状态
- self_id:以后服务器的 myid
- self_zxid:以后服务器保留数据的最大 zxid
- vote_id:被推举的服务器的 myid
- vote_zxid:被推举的服务器上所保留的数据的最大 zxid
-
投票流程
- 自增选举轮次
Zookeeper 规定所有无效的投票都必须在同一轮次中。每个服务器在开始新一轮投票是,会先对本人保护的 logicClock 进行自增
- 初始化选票
播送投票前服务器会现将本人的投票箱清空
- 发送初始化选票
每个服务器最开始都是通过播送把票投给本人
- 接管内部选票
服务器会尝试从其余服务器获取投票,并计入本人的投票箱。
-
判断选举轮次
- 如果内部投票的 logicClock 大于本人的,则阐明该服务器选举轮次落后了,服务器会立刻清空本人的投票箱并将本人的 logicClock 更新为收到的 logicClock,再比照本人之前的投票和收到的投票以确定是否须要变更本人的投票,最终再次将本人的投票播送进来。
- 内部投票的 logicClock 小于本人的,服务器间接疏忽,解决下一个投票
- logicClock 相等,选票 PK
-
选票 PK
- 先比拟 zxid,若收到的票 zxid 较大,将本人票中的 vote_zxid 与 vote_myid 更新为 zxid 比拟大的;并将收到的票及本人更新后的票放入本人的票箱
- zxid 雷同,比拟 myid,如果收到的票 myid 大,将 vote_myid 更新为较大的并播送进来,将收到的票及本人更新后的票放入本人的票箱
- 统计选票
如果曾经确定有过半服务器认可了本人的投票(也可能是更新后的投票),则终止投票,否则持续承受其余服务器的投票
- 更新服务器状态
更新服务器状态为 LEADING 或者 FOLLOWING
- 自增选举轮次
集群初始化时的选举
Follower 解体后的选举
leader 解体后的选举(不想画图了。。)
- 从新选举出 Leader
- 老 Leader 复原后成为 Follower
Zookeeper 相干利用:
配置核心
注册核心
Zookeeper 实现分布式锁
Zookeeper 实现分布式锁原理就是Watch 机制 + 长期程序节点。
头脑风暴
- 争抢锁,只有一个人能取得锁?leader 节点只有一个,创立 leader 节点胜利的获取锁。
- 取得锁的人出问题,死锁问题?长期节点(session)
- 取得锁的人胜利了,要开释锁?被动放弃领导权
- 锁被开释、删除,他人怎么晓得的?
4-1 被动轮询,心跳?弊病:提早,压力
4-2 watch:解决提早问题。弊病:压力
4-3 多个 watch 同时触发,负载压力?程序节点,watch 前一个(按序列程序顺次 watch 前一个),最小的取得锁!老本:一旦最小的开释了锁,Zookeeper 只给第二个发事件回调,资源耗费压力小
非偏心锁实现
- 多个客户端发动创立 leader 节点申请,争抢到的客户端创立 leader 节点,取得锁
- 没有创立胜利的客户端成为 follower 节点,并发动一个 watch 监听 leader 节点
- 当客户端开释锁时,leader 被动放弃领导权,间接删除 leader 节点;当 leader 过程宕机,与 Zookeeper 之间的 session 完结,leader 节点也会被删除
- 当 leader 节点被删除,watch 触发,剩下的客户端开始竞争创立节点,反复步骤一
- 小结
Zookeeper 写性能不高,如果有上万个客户端参加锁竞争,就会有上万个写申请 (创立 leader 节点) 发送给 Zookeeper,Zookeeper 集群负载压力过大;
当开释锁,leader 被动放弃领导权时,又会触发 watch,须要给每个客户端进行告诉,负载压力过大
偏心锁实现
- 客户端都创立 /Zookeeperroot/leader 节点
- 因为是程序节点,每个客户端都能创立胜利,每个客户端会判断本人是不是最小序列的节点,是则成为 leader,不是则成为 follower 节点
- 当客户端开释锁时,leader 被动放弃领导权,间接删除 leader 节点;当 leader 过程宕机,与 Zookeeper 之间的 session 完结,leader 节点也会被删除
- 偏心锁实现时,每个 follower 节点只须要 wacth 比它前一个序列的节点即可。当 leader 节点被删除,只有后一个 follower 节点失去告诉,而后成为 leader 节点。
- 当 leader 节点没有放弃领导权,其中有其它客户端宕机导致该 follower 节点不可用时,宕机节点的后一个节点不会间接成为 leader 节点,它会判断本人是不是最小的节点,如果不是,则 watch 前一个序列节点;如果是,则成为 leader 节点。