Zookeeper 基础知识

 

zookeeper 动物园管理员,可以用来管理 hadoop(大象)、hive(蜜蜂)、pig(小 猪)、tomcat(猫)等等。

Apache Hbase 和 Apache Solr 的分布式集群都用到了 zookeeper,Dubbo中也要用到zookeeper。

 

Zookeeper是一个高性能、高可用的分布式管理与协调框架,主要功能包括:配置管理、命名服务、分布式锁、集群管理、发布/订阅、队列管理。

 

 


 

 

 

ZooKeeper 的作用(应用场景)

1、配置管理

项目中有各种配置,比如数据库连接配置,springboot、springcloud的yml配置,集群各节点的配置,等等。

当我们只使用少数几台服务器、配置文件很少的时候,配置文件可以直接放在这些服务器上。

但做分布式项目的时候,往往有很多集群,集群节点很多,各种配置文件一大堆,这时候就需要使用zk来集中管理配置。

常见的有,使用zk来管理HBase集群的配置信息,管理Kafka的broker信息,Dubbo中使用zk来管理各服务节点的信息、实现服务治理(相当于SpringCloud中的Eureka)。

 

 

2、命名服务

访问服务时,直接使用服务所在机器的ip地址很麻烦,全是数字、机器又多,那么多ip,不好记。

可以把集群各节点提供的服务的名称、机器ip注册到ZK上,在项目中直接使用服务名,向ZK请求某个服务时,ZK会选择合适的节点(ip)来提供服务。

 

 

3、分布式锁

除了redis可以实现分布式锁,zk也可以。

 

 

4、 集群管理

在分布式的集群中,由于各种原因,比如硬件故障、网络故障、并发量剧增等,经常要增减节点数量。

添加新的节点、或者旧的节点下线,集群中的各节点需要感知集群节点的变化。zk server可以存储集群各节点(client)的信息,集群各节点再从zk server上获取其它集群的信息。

Dubbo的服务治理就是用ZK实现的。

 

 

5、发布/订阅

利用zk的观察/通知机制。zk client订阅某个znode,这个znode变化时,zk server会通知对应的zk client获取znode的最新数据。

 

 

6、实现队列

利用zk执行写请求的顺序一致性来实现(paxos算法)。

 

 


 

 

 

Zookeeper的数据模型

树结构,/是根节点,节点叫做znode,一个znode对应一个文件目录。

一个znode都代表1个zk client,用来存储、管理一个zk client的数据。

每个znode都可以有子节点,即znode可以嵌套。

 

 

有四种类型的znode

  • PERSISTENT  持久化。一个节点断开与zk server的连接后,zk server会保留该节点对应的znode

  • PERSISTENT_SEQUENTIAL  持久化顺序编号。客户端与zookeeper断开连接后,zk server会保留该节点对应的znode

  • EPHEMERAL  临时。一个节点断开与zk server的连接后,zk server会删除该节点对应的znode

  • EPHEMERAL_SEQUENTIAL   临时顺序编号。一个节点断开与zk server的连接后,zk server会删除该节点对应的znode

 

SEQUENTIAL 顺序编号指的是,创建一个znode时会自动在节点名上加一个整数作为后缀。

这个整数由父节点维护,比如最新的一个SEQUENTIAL znode到5了,那下一个创建SEQUENTIAL  znode就是6。

 

 

临时节点常用于实现分布式锁

服务节点先检测是否有某个临时节点,比如/ticket_lock,没有此节点,接设置此节点,持有锁;如过此节点已存在,就说明锁已经被某个节点获取、持有。

如果获取到锁的服务节点故障,断开连接后会自动删除此临时节点,释放锁。

 

 

 


 

 

 

zkServer的集群模式

zk server一般都要集群,保证zk server的高可用。zk server的集群一般要读写分离,搞成分布式读写的形式。

 

 

  

zkServer有3种角色

  • leader   负责处理zk client的写请求(更新znode),一个zk集群只有一个leader
  • follower  同步leader的数据,负责处理zk client的读请求(获取znode中的数据),并参与leader的选举
  • observer  处理zk client的读请求,但不能参与leader的选举,相当于临时工,没有编制

 

 

有follower就够了,为什么还要使用observer?

  • 减少选举的时间花销。

  假设follower5台、observer6台,选举新的leader时只需要等待3台机器同意;如果10台全是follower,需要等待6台机器同意,大大增加了选举的时间花销。

 

  • 提高可用性。observer只是临时工,宕掉一半集群就不可用,指的是follower宕掉一半,observer不参与数量统计,就算observer全部宕掉,也没关系。

    假设follower5台、observer8台,宕掉所有的observer、2台follower总共10台机器,集群仍然可用;如果13台全是follower,宕掉7台机器集群就不可用;显然使用observer可用性更高。

 

observer可以看做无选举、投票权的follower,主要是为了协助 follower 处理更多的读请求。如果zkCli非常多、zkServer集群的读请求负载很高,可以设置一些 Observer,提高读请求的吞吐量。

 

 

zkServer集群至少需要3台机器,为何官方推荐集群的zkServer数量为单数?

比如zk server数量为5,挂掉3个,集群就不可用;数量为6,还是挂掉3个,集群就不可用。

5台、6台的容灾能力是一样的,少用1台机器还可以减少点成本。

 

 


 

 

 

zkServer如何处理zkCli的请求?

读请求

zk集群的所有节点都可以处理读请求,自己收到读请求直接就处理了。

 

 

写请求

由leader处理写请求,follower、observer收到写请求时转交给leader处理。leader使用paxos算法来处理写请求:

leader将写请求都放到一个队列中,并给写请求分配一个唯一的编号,按照先进先出的顺序处理。执行某个写请求时,leader先向follower发起投票,是否要执行这个写请求,如果超过半数同意,leader就会执行这个写请求。同一时刻,leader只会执行一个写请求,来保证数据的一致性。

如果某个follower、observer同步数据时,比如一个follower同步编号为99的写操作时,发现编号为100的写操作之前已经同步了,意识到自己的数据不一致,马上停止对外服务,并从leader同步全量数据。

 

准确来说不算是投票。因为follower、observer要从leader同步数据,leader先执行一个写请求,follower、observer再同步这个写操作引起的数据更新,这2步作为一个事务来处理。

如果有一半以上的节点同步成功,就认为这个写操作执行成功,提交事务。至于其他尚未同步成功的,如果机器故障下线了,那也不用去管它是否同步了;如果是网络延迟等原因,过会儿会自动从leader同步,也不用去管。

如果同步成功的节点数量没达到一半,就认为同步失败,在已执行这个写操作的机器上进行回滚。

 

其实leader处理读、写请求都是放在一个队列中的,只不过读请求不发起投票。

 

 


  

 

 

Zookeeper的特点

  • 顺序一致性:zkServer使用paxos算法来处理请求,将请求放在队列中,先进先出,请求的执行顺序与发送顺序一致。写代码时可以利用这个特性来实现更高层次的同步。
  • 数据更新原子性:一次写操作即一个事务,要么成功(都应用、同步到所有节点),要么失败(所有节点都不使用这次数据更新)。
  • 单一视图: zk client无论连接到哪个zk server,读到的数据都是一样的
  • 可靠性(高可用性):zk server往往要集群,只要半数以上的节点可以正常工作,zk server集群就可以对外提供服务。(observer不参与数量统计)
  • 实时性: zkCli读取到的是zkServer上最新的数据
  • 高性能:zk server将全量数量存储在内存中,性能极高,尤其是在读的时候。写(更新znode)的时候,要把更新从内存同步到文件,性能稍低。

 

 


 

 

 

Zookeeper的工作原理

zk的核心机制是原子广播,这个机制保证了zk server之间的数据同步。

 

实现原子广播的协议是Zab协议,Zab协议有3种模式

  • 恢复模式。leader故障后自动进入恢复模式,将集群恢复到正常工作状态。先从follower中选出一个新的leader,其它follower从新的leader处同步数据,大多数follower同步完后恢复模式就结束了。
  • 同步模式。follower从leader处同步数据。同步模式也是恢复模式的一部分。
  • 广播模式。leader处理写请求时,广播通知follower发起投票,半数以上的follower同意后,leader执行写请求(修改自身的znode),执行后将修改、更新广播给follower、observer,完成同步。

   

 


 

 

 

leader选举

zkServer在选举leader过程中的状态

  • LOOKING:leader宕掉了,正在选举新的leader
  • LEADING:当前zkServer成为leader
  • FOLLOWING:当前zkServer是follower,同步leader的数据
  • OBSERVING:当前zkServer是observer,同步leader的数据

 

 

myid

唯一标识集群中的一个zkServer

 

 

zxid

zxid其实是一个ReentranReadWriteLock,为保证数据一致性,一个节点同一时刻只执行一个读写操作,自然要加锁。follower、observer只是对外不处理写请求,同步leader数据时依然要同步写操作。

zxid的前32位表示epoch(纪元、时代),一个leader对应一个epoch(时代),换了新的leader,epoch会自动使用新值。

zxid的后32位表示xid,每一个写操作都是一个事务,xid即事务id。

 

myid标识的是zkServer节点,zxid标识的是数据版本。

 

 

Logicalclock  逻辑时钟

逻辑时钟是选举时的一个概念,其值就是zxid中epoch的值。选举出新的leader,开启了新leader的统治时代,新纪元|时代就此诞生。

 

 

leader的选举时机

  • 集群启动还没有leader时
  • leader宕机时

 

 

leader的选举机制|算法

集群没有leader时,所有节点都是LOOKING状态。

所有follower都参与投票,投的都是自己,写上自己的myid、zxid,广播出去。

比较zxid,先选epoch大的,再从里面选xid大的。epoch越大、xid越大,说明数据越新。如果zxid相同,选择myid大的。

选出新的leader后,leader变为LEADING状态,follower变为FOLLOWING状态,observer变为OBSERVING状态。

  

 


 

 

Zookeeper的观察/通知机制

一个zkCli可以观察(watch)某个znode,一旦指定的znode发生改变,zkServer会通知观察此znode的zkCli。

不使用zkCli轮询zkServer的方式,一者开销大,二者轮询大多数时候都是无效的,znode发生变化时由zkServer通知对应的zkCli。

 

posted @ 2019-06-25 17:11  chy_18883701161  阅读(5086)  评论(0编辑  收藏  举报