Zookeeper总结

概念简述

  • 分布式系统协调服务的中间件
  • 能够基于Zookeeper实现发布/订阅、负载均衡、分布式协调/通知、master选举、分布式锁、分布式队列等

简单说下分布式系统特色

  • 多台计算机组成一个总体,一个总体一致对外而且处理同一请求
  • 内部的每台计算机均可以互相通讯(REST/RPC)
  • 客户端到服务端的一次请求到响应结束会经历多台计算机

特性

  • 顺序一致性:客户端的更新将按发送顺序应用
  • 原子性:事务要么所有成功,要么所有失败
  • 单一视图:客户端链接集群中的任一Zookeeper节点,数据都是一致的
  • 可靠性:每次对Zookeeper的操做状态都会保存在服务端,一旦应用了更新,它将从那时起持续到客户端覆盖更新
  • 实时性:客户端能够读取到Zookeeper服务端的最新数据

Zookeeper结构模型

Zookeeper的数据保存在内存中。Zookeeper容许分布式进程经过共享的层次结构命名空间进行相互协调,层次结构命名空间由ZooKeeper中的数据寄存器——Znode组成,Znode相似于文件和目录。node

  • 树型结构,相似linux的目录结构或HTML
  • 每一个Zookeeper节点都有各自的版本号,每当节点数据变化,该节点的版本号会累加
  • 每一个Zookeeper节点存储的数据不宜过大,几kb便可
  • 节点能够设置权限来限制访问

ZNode(数据节点)结构

每一个ZNode由两部分组成:linux

  • stat:状态信息;包括一个数据节点的全部状态信息,包括事务ID、版本信息和子节点个数等。
  • data:数据内容

node模型,父node会有多个子node服务器

image.png

节点类型

  • 持久节点

    节点建立后就一直存在,直到有删除操做来主动清除这个节点,不会随会话失效而消失。session

  • 临时节点

    节点生命周期和客户端会话绑定。客户端会话失效(是会话失效,不是链接断开)时,节点消失。数据结构

  • 顺序节点

    不是一种类型,持久和临时节点都会有顺序节点,每一个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.png

##### 消息广播和崩溃恢复

*   消息广播
    
    过半服务器和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

集群初始化时的选举

image

Follower崩溃后的选举

image.png

leader崩溃后的选举(不想画图了。。)
  • 从新选举出Leader
  • 老Leader恢复后成为Follower

Zookeeper相关应用:

配置中心

注册中心

Zookeeper实现分布式锁

Zookeeper实现分布式锁原理就是Watch机制+临时顺序节点

头脑风暴
  1. 争抢锁,只有一我的能得到锁?leader节点只有一个,建立leader节点成功的获取锁。
  2. 得到锁的人出问题,死锁问题?临时节点(session)
  3. 得到锁的人成功了,要释放锁?主动放弃领导权
  4. 锁被释放、删除,别人怎么知道的?

    4-1 主动轮询,心跳?弊端:延迟,压力

    4-2 watch: 解决延迟问题。 弊端:压力

    4-3 多个watch同时触发,负载压力?顺序节点,watch前一个(按序列顺序依次watch前一个),最小的得到锁!成本:一旦最小的释放了锁,Zookeeper只给第二个发事件回调,资源消耗压力小

非公平锁实现(实现有弊端)
  1. 多个客户端发起建立leader节点请求,争抢到的客户端建立leader节点,得到锁
  2. 没有建立成功的客户端成为follower节点,并发起一个watch监听leader节点
  3. 当客户端释放锁时,leader主动放弃领导权,直接删除leader节点;当leader进程宕机,与Zookeeper之间的session结束,leader节点也会被删除
  4. 当leader节点被删除,watch触发,剩下的客户端开始竞争建立节点,重复步骤一
  5. 小结

    Zookeeper写性能不高,若是有上万个客户端参与锁竞争,就会有上万个写请求(建立leader节点)发送给Zookeeper,Zookeeper集群负载压力过大;

    当释放锁,leader主动放弃领导权时,又会触发watch,须要给每一个客户端进行通知,负载压力过大

公平锁实现
  1. 客户端都建立/Zookeeperroot/leader节点
  2. 因为是顺序节点,每一个客户端都能建立成功,每一个客户端会判断本身是否是最小序列的节点,是则成为leader,不是则成为follower节点
  3. 当客户端释放锁时,leader主动放弃领导权,直接删除leader节点;当leader进程宕机,与Zookeeper之间的session结束,leader节点也会被删除
  4. 公平锁实现时,每一个follower节点只须要wacth比它前一个序列的节点便可。当leader节点被删除,只有后一个follower节点获得通知,而后成为leader节点。
  5. 当leader节点没有放弃领导权,其中有其它客户端宕机致使该follower节点不可用时,宕机节点的后一个节点不会直接成为leader节点,它会判断本身是否是最小的节点,若是不是,则watch前一个序列节点;若是是,则成为leader节点。
相关文章
相关标签/搜索