概念简述
- 分布式系统协调服务的中间件
- 能够基于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将处理结果返回客户端
##### 音讯播送和解体复原* 音讯播送 过半服务器和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节点。