zookeeper知识点总结

zk特性

 顺序一致性:从同一个客户端发起的事务请求,最终会严格按照顺序被应用到zookeeper中

 原子性:所有的事务请求的处理结果在整个集群中的所有机器上的应用情况是一致的,也就是说,要么整个集群中的所有机器都成功应用了某一事务、 要么全都不应用 对应每一个事务请求,ZooKeeper 都会为其分配一个全局唯一的事务ID,用 ZXID 表示,通常是一个64位的数字。每一个 ZXID 对应一次更新操作,从这些 ZXID 中可以间接地识别出 ZooKeeper 处理这些事务操作请求的 全局顺序。

 可靠性:一旦服务器成功应用了某一个事务数据,并且对客户端做了响应,那么这个数据在整个集群中一定是同步并且保留下来的

 实时性:一旦一个事务被成功应用,客户端就能够立即从服务器端读取到事务变更后的最新数据状态;(zookeeper仅仅保证在一定时间内,近实时)

 单一视图:无论客户端连接到哪个服务器,所看到的模型都是一样 任何节点上的数据都是一样的,所以客户端访问任意节点都看到是相同的数据

 Watcher(事件监听器):是 ZooKeeper 中一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些 Watcher, 并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去。该 机制是 ZooKeeper 实现分布式协调服务的重要特性。

zk数据模型

zookeeper的数据模型和文件系统类似,每一个节点称为:znode. 是zookeeper中的最小数据单元。每一个znode上都可以 保存数据和挂载子节点。 从而构成一个层次化的属性结构 节点特性

 持久化节点:节点创建后会一直存在zookeeper服务器上,直到主动删除

 持久化有序节点:每个节点都会为它的一级子节点维护一个顺序

 临时节点:临时节点的生命周期和客户端的会话保持一致。当客户端会话失效,该节点自动清理, 比如当客户端连接服务端时建立了一个临时节点,当客户端与服务器因网络原因断开了那么该临时节点就会被删除

 临时有序节点:在临时节点上多勒一个顺序性特性

 ACL:zookeeper提供控制节点访问权限的功能,用于有效的保证zookeeper中数据的安全性。避免误操作而导致系统出现重大事故。

 更新数据时:悲观锁:就是独占,我锁定资源只有当我释放资源了别人才可用(包括了不让别人读取); 乐观锁:就是大家可以用资源,当你写入更新的时候去判断之前数据状态是否已经被更改,如果更改就是有操作过了,那么就回滚。 跟mysql中的悲观与乐观锁相似 ZooKeeper的数据节点采用了悲观锁的思想,用一个版本号做检验状态,每次要写入数据、更改数据都带上版本号做验证,如果是-1就是用最新版本号,不做验证

集群角色

 leader:提供读和写能力 leader:处理事务请求,保证事务一致性; 1、leader是zookeeper集群的核心, 2、事务请求的唯一调度者和处理者,保证集群事务处理的顺序性 3、集群内部各个服务器的调度者 4、也就是说只要是有事物请求那么就一定会由leader进行处理,如果一个事物请求到了follower节点,那么也会转发到leader节点进行处理

 follower

提供读能力 follower:处理非事务请求,并转发客户端事务请求到leader,并参与选举投票 1、处理客户端非事务请求,以及转发事务请求给leader服务器 2、参与事务请求提议(proposal)的投票(客户端的一个事务请求,需要半数服务器投票通过以后才能通知leader commit; leader会发起一个提案,要求follower投票) 3、参与leader选举的投票

 observer:处理客户的非事务请求,不参与选举投票,只是为了分担数据做动态扩展,可有可无。 1、观察zookeeper集群中最新状态的变化并将这些状态同步到observer服务器上 2、因为observer不参与投票,所以增加observer不影响集群中事务处理能力,同时还能提升集群的非事务处理能力

数据存储

 内存数据和磁盘数据

1.zookeeper会定时把数据存储在磁盘上。 2.DataDir = 存储的是数据的快照 快照: 存储某一个时刻全量的内存数据内容 3.DataLogDir 存储事务日志

 日志:zookeeper 有三种日志 zookeeper.out 1.运行日志 2.快照,存储某一时刻的全量数据 3.事务日志 事务操作的日志记录

zk的leader选举

 zk节点的几种状态:Looking:系统刚启动时或者Leader崩溃后正处于选举状态;初始状态 Following:Follwoer节点所处的状态,Follower与Leader处于数据同步阶段; Leading:Leader所处状态,当前集群中有一个Leader为主进程。 Observering:Obersver所处状态

 leader选举时状态类型

  1. ZooKeeper启动时所有节点初始状态为Looking,这时集群会初始选举出一个Leader节点,选举出的Leader节点切换为Leading状态;
  2. 当节点发现集群中已经选举出Leader则该节点会切换到Following 状态,然后和Leader节点保持同步;
  3. 当Following节点与Leader失去联系时Follower节点则会切换到Looking状态,开始新一轮选举;
  4. 在ZooKeeper的整个生命周期中每个节点都会在Looking、Following、Leading状态间不断转换。

 成为leader的条件:选epoch最大的; epoch相等,选zxid最大的 epoch的zxid都相等,选择server id最大的(就是配置zoo.cfg中的myid) 解释: 1、ZXID,事务ID,用来唯一标识一次服务器状态的变更 2、服务器SID,一个数字,通过配置文件配置(myid),唯一 3、epoch是指:年代,一个领导挂了,另一个领导上任,现在就是新领导的时代了,当产生新领导,事务编号就从0开始

 最初启动时投票

1.每个服务器发送一个投票(SID,ZXID),其中sid是自己的myid,初始阶段都将自己投为Leader。 2.处理投票,针对每个投票都按上述“成为leader条件”规则与自己的投票PK,PK后依据情况是否更新投票,再发送给其他机器。 3.统计投票:每次投票后,服务器统计所有投票,判断是否有过半的机器收到相同的投票,如果某个投票达到一半的要求,则认为该投票提出者可以成为Leader。 4.改变服务器状态:一旦确定了Leader,每个服务器都更新自己的状态,Leader变更为Leading,Follower变更为Following 5.正常情况下一旦选出一个Leader则一直会保持,除非Leader服务器宕掉,则再进行重新选举。

 运行时的投票

1、若超时时间内Leader没有接收到来自过半Follower节点的心跳检测或TCP连接断开,那Leader会结束当前的领导,自动切换到Looking状态 2、所有Follower节点(除了observer节点)也会放弃该Leader节点切换到Looking状态,然后开始新一轮选举

 集群一般为什么都会配置奇数节点

1、因为集群搭建的服务想要做什么一般都会遵循一半以上的节点成功才算成功 2、所以当为2个节点时,容错率为0,:3个节点时,容错率为1,4个节点容错率为1(总节点数为4所以需2个以上的节点同意或成功才行),5个节点容错率为2,6个节点容错率为2 3.所以2n个节点和2n-1个节点的容错率是一样的,所以为什么还要多配置一个节点呢?

zk作用

 ID生成器

实现方式有两种,一种通过节点,一种通过节点的版本号 1、通过创建ZK的有序持久模式的节点,可以生成全局唯一的ID(即使有节点删除也不会重复,就行数据库id一样自增) 2、节点创建完成后,会返回节点的完整的层次路径,生成的序号,放置在路径的末尾。一般为10位数字字符。如节点:qijx000000000001 3、通过截取路径末尾的数字,作为新生成的ID。

 分布式锁

参考博客:https://blog.csdn.net/koflance/article/details/78616206

  互斥锁

互斥锁创建: 1、首先创建一个根节点如:root_lock 2、其次所有客户端开始创建(create)一个有序临时节点(为啥不是持久节点呢?因为万一客户端与服务端断开了那么这个持久节点不能删除就相当于死锁了),例如“root_lock/guid-lock-”,其中guid可以是你客户端的唯一识别序号,如果发生前面说的创建失败问题,需要使用guid进行手动检查。 3、然后调用getChildren(watch=false)查询根节点root_lock下创建的子节点列表,注意wtach设置为false,以避免羊群效应(Herd Effect),即同时收到太多无效节点删除通知 4、然后从这个列表中,判断自己客户端创建的节点序号是否是最小,如果是则直接返回true(此客户端获得锁) 5、否则从获取的子节点的列表中找到比自己次小的节点(也就是当前客户端创建的节点的上一个节点)调用exist(watch=true)方法。如果exist返回false(不存在),则从第3步继续开始,如果exist返回true(存在),则等待exist的哨兵(watch)回调通知,等待次小节点被删除通知 6、如果当收到次小节点被删除的通知时,再从步骤3开始判断自己是否是最小节点。。。 7、最后,客户端unlock释放锁只需要调用delete删除掉节点即可。

  读写锁

一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读锁又有写锁。 读锁 1、首先创建一个根节点如:root_lock 2、其次所有客户端开始创建(create)一个有序临时节点,例如“root_lock/read-guid-lock-” 3、调用getChildren(watch=false)获取获取子节点列表 4、这个列表中,判断是否有序号比自己小、且路径名以“write-”开头的节点,如果没有,则直接获取读锁,如果有则再从列表中获取当前节点的上一位,且路径名以write-开头的节点,调用exist(watch=true)方法加入监听,如果exist返回false(说明没有写锁)则从3开始继续执行, 如果exist返回true,则等待exist的哨兵(watch)回调通知,等待写锁释放之后再开始从3开始执行 写锁 1、首先创建一个根节点如:root_lock 2、其次所有客户端开始创建(create)一个有序临时节点,例如“root_lock/write-guid-lock-” 3、调用getChildren(watch=false)获取获取子节点列表 4、从这个列表中,判断自己创建的节点序号是否是最小,如果是则直接返回true(获得锁),如果否,则选取次小节点调用 exist(watch=true)方法,如果exist返回false则继续执行步骤3,如果exist返回true,则等待exist的哨兵(watch)回调通知,收到通知后再执行步骤3 最后,客户端unlock只需要调用delete删除掉节点即可。

优点

可实现分布式共享锁Shared Locks或读写锁Read/Write Locks

  缺点

1、没有解决重入锁问题,因为采用的是有序临时节点,因此多次调用create并不会触发KeeperException.NodeExists异常,从而无法实现锁重入功能,如果需要解决,需要先进行判断当前节点是否已经存在 2/因为是顺序节点所以,这是一个公平锁,无法实现非公平锁

 注册中心(命名服务)

服务注册: 1、服务提供者在启动的时候,会在ZooKeeper上注册服务。所谓注册服务,其实就是在ZooKeeper上自己定义的一个节点下如:/providers下创建一个临时子节点,并写入自己的URL地址 这就代表了一个服务提供者 2、增加服务提供者:也就是在providers下面新建子节点。一旦服务提供方有变动,zookeeper就会把最新的服务列表推送给消费者。 3、减少服务提供者:所有提供者在ZooKeeper上创建的节点都是临时节点,利用的是临时节点的生命周期和客户端会话相关的特性,因此一旦提供者所在的机器出现故障导致该提供者无法对外提供服务时,该临时节点就会自动从ZooKeeper上删除,同样,zookeeper会把最新的服务列表推送给消费者。 4、ZooKeeper宕机之后:消费者每次调用服务提供方是不经过ZooKeeper的,消费者只是从zookeeper那里获取服务提供方地址列表然后缓存下来。所以当zookeeper宕机之后,不会影响消费者调用服务提供者,影响的是zookeeper宕机之后如果提供者有变动,增加或者减少,无法把最新的服务提供者地址列表推送给消费者,所以消费者感知不到。 服务发现: 1、服务消费者,从提供者地址列表中,基于软负载均衡算法,选一个提供者进行调用,如果调用失败,再选另一个提供者调用。

 集群管理Master-slave选举

1、原理:利用强一致性同时创建同一个临时节点,最后只能一个成功。 成功那个节点会返回成功状态,其他节点返回异常,成功的那个就成为master,其他节点就改成slave。 2、当这个master节点与zk集群服务端断开连接时,该临时节点会被删除,同时watcher机制会通知其他节点,然后就会触发新一轮的创建节点争抢master步骤

 数据发布与订阅(配置中心disconf)

发布/订阅系统一般有两种设计模式,分别是推(Push)和拉(Pull)模式。 - 推模式 服务端主动将数据更新发送给所有订阅的客户端 - 拉模式 客户端主动发起请求来获取最新数据,通常客户端都采用定时轮询拉取的方式 ZooKeeper 采用的是推拉相结合的方式: 客户端想服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应 的客户端发送Watcher事件通知,客户端接收到这个消息通知后,需要主动到服务端获取最新的数据

 

zookeeper知识点总结