Zookeeper笔记3——原理及其安装使用

Zookeeper到底能干什么?

1.配置管理:这个好理解。分布式系统都有好多机器,Zookeeper提供了这样的一种服务:一种集中管理配置的方法,我们在这个集中的地方修改了配置,所有对这个配置感兴趣的都可以获得变更。这样就省去手动拷贝配置了,还保证了可靠和一致性。

在分布式系统中,常会遇到这样的场景: 某个Job的很多个实例在运行,它们在运行时大多数配置项是相同的,如果想要统一改某个配置,一个个实例去改,是比较低效,也是比较容易出错的方式。通过ZooKeeper可以很好的解决这样的问题,下面的基本的步骤:

  • 将公共的配置内容放到ZooKeeper中某个ZNode上,比如/service/common-conf
  • 所有的实例在启动时都会传入ZooKeeper集群的入口地址,并且在运行过程中Watch /service/common-conf这个ZNode
  • 如果集群管理员修改了了common-conf,所有的实例都会被通知到,根据收到的通知更新自己的配置,并继续Watch /service/common-conf

   如下图:

  

 这样就可以实现了热更新,无需一个个手动配置机器集群,无需重启,重启还可能引发灾难性问题。

 

 

2.名字服务:

  在分布式环境下,经常需要对应用/服务进行统一命名,便于识别不同服务。 
    a)类似于域名与ip之间对应关系,ip不容易记住,而域名容易记住。 
    b)通过名称来获取资源或服务的地址,提供者等信息。

  按照层次结构组织服务/应用名称。 
    a)可将服务名称以及地址信息写到ZooKeeper上,客户端通过ZooKeeper获取可用服务列表类。

3.分布式锁:处于不同节点上不同的服务,它们可能需要顺序的访问一些资源,这里需要一把分布式的锁。

     1、ZooKeeper是强一致的。比如各个节点上运行一个ZooKeeper客户端,它们同时创建相同的Znode,但是只有一个客户端创建成功。

     2、实现锁的独占性。创建Znode成功的那个客户端才能得到锁,其它客户端只能等待。当前客户端用完这个锁后,会删除这个Znode,其它客户端再尝试创建Znode,获取分布式锁。

     3、控制锁的时序。各个客户端在某个Znode下创建临时Znode,这个类型必须为CreateMode.EPHEMERAL_SEQUENTIAL,这样该Znode可掌握全局访问时序。

4.集群管理:应用集群中,我们常常需要让每一个机器知道集群中(或依赖的其他某一个集群)哪些机器是活着的,并且在集群机器因为宕机,网络断链等原因能够不在人工介入的情况下迅速通知到每一个机器。或者有新的机器节点加入,可以自动通知其他机器。

 

 

Zookeeper设计目:

  1.最终一致性:client不论连接到哪个Server,展示给它都是同一个视图,这是zookeeper最重要的性能。 

  2.可靠性:具有简单、健壮、良好的性能,如果消息被到一台服务器接受,那么它将被所有的服务器接受。 

  3.实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。 

  4.等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个client都能有效的等待。 

  5.原子性:更新只能成功或者失败,没有中间状态。 

  6.顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。

 

Zookeeper本身就是一个分布式系统,注意的是,我们往往会部署奇数个ZK服务器,因为根据Paxos算法可以知道,是基于少数服从多数的原则,比如,一共四台机器,有可能会出现2:2的情况。

Paxos算法是Zookeeper的核心精髓,但是Zookeeper并没有直接使用Paxos算法,而是基于Paxos算法的思想产生Zab协议。

Zab协议包括两个核心:

  第一,原子广播:客户端提交事务请求时Leader节点为每一个请求生成一个事务Proposal,将其发送给集群中所有的Follower节点,收到过半Follower的反馈后开始对事务进行提交,ZAB协议使用了原子广播协议;在ZAB协议中只需要得到过半的Follower节点反馈Ack就可以对事务进行提交,这也导致了Leader几点崩溃后可能会出现数据不一致的情况,ZAB使用了崩溃恢复来处理数字不一致问题;消息广播使用了TCP协议进行通讯所有保证了接受和发送事务的顺序性。广播消息时Leader节点为每个事务Proposal分配一个全局递增的ZXID(事务ID),每个事务Proposal都按照ZXID顺序来处理;

Leader节点为每一个Follower节点分配一个队列按事务ZXID顺序放入到队列中,且根据队列的规则FIFO来进行事务的发送。Follower节点收到事务Proposal后会将该事务以事务日志方式写入到本地磁盘中,成功后反馈Ack消息给Leader节点,Leader在接收到过半Follower节点的Ack反馈后就会进行事务的提交(值得注意的是,ZAB 提交事务并不像 2PC 一样需要全部 follower 都 ACK,只需要得到 quorum (超过半数的节点)的 ACK 就可以了。),以此同时向所有的Follower节点广播Commit消息,Follower节点收到Commit后开始对事务进行提交;

  第二,Master选举:节点在一开始都处于选举阶段,只要有一个节点得到超半数节点的票数,它就可以当选准 leader。只有到达 Phase 3 准 leader 才会成为真正的 leader。这一阶段的目的是就是为了选出一个准 leader,然后进入下一个阶段。

协议并没有规定详细的选举算法。主要的两种选举算法:1.Base Paxos(即笔记2中的Paxos)。2.Fast Paxos(Fast Leader Election算法)

 

Fast Leader Election算法:

 

epoch:选举轮数,即周期

Zxid: Zxid 是一个 64 位的数字,其中低 32 位是一个简单的单调递增的计数器,针对客户端每一个事务请求,计数器加 1;而高 32 位则代表 Leader 周期 epoch 的编号,每个当选产生一个新的 Leader 服务器,就会从这个 Leader 服务器上取出其本地日志中最大事务的ZXID,并从中读取 epoch 值,然后加 1,以此作为新的 epoch,并将低 32 位从 0 开始计数。

 FLE 会选举拥有最新提议历史(lastZixd最大)的节点作为 leader,这样就省去了发现最新提议的步骤。这是基于拥有最新提议的节点也有最新提交记录的前提。

 

成为 leader 的条件

  1. epoch最大的
  2. epoch相等,选 zxid 最大的
  3. epochzxid都相等,选择server id最大的(就是我们配置zoo.cfg中的myid

 

节点在选举开始都默认投票给自己,当接收其他节点的选票时,会根据上面的条件更改自己的选票并重新发送选票给其他节点,当有一个节点的得票超过半数,该节点会设置自己的状态为 leading,其他节点会设置自己的状态为 following。

选举过程

  

1. 每个从节点都向其他节点发送选自身为Leader的Vote投票请求,等待回复;

2. 从节点接受到的Vote如果比自身的大(ZXID更新)时则投票,并更新自身的Vote,否则拒绝投票;

3. 每个从节点中维护着一个投票记录表,当某个节点收到过半的投票时,结束投票并把该从节点选为Leader,投票结束;

 

 Zookeeper的安装以及集群的搭建如下:

1.首先去官网https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/下载,注意,一定要下载stable版本的,因为这是稳定版。如图:

下载后,解压,简历一个Zookeeper-Cluster文件夹,将解压好的Zookeeper复制进这个文件夹。复制三份。如图:

 在每个zookeeper目录下建立一个data文件夹,如下图:

 

 现在我们要对每一个zookeeper的配置文件进行配置。如下图:

注意zoo.cfg是由zoo_sample.cfg改名来的,不改名不行的。

 

 对zoo.cfg进行配置如下图:

 

 还要在每一个zookeeper的data文件下建立一个无后缀的myid文件写入对应的服务编号,如果是server.1就写入一个1  如下图:

 

 

最后首先就是启动每一个zookeeper的server,再随意启动一个zookeeper客户端。如下图:

 

再启动其中一个zookeeper客户端。 如下图:

 

Zookeeper使用的命令:

1.create /zk-node    标识在根目录下创建一个zk-node的节点

现在我们通过ls命令查看有没有创建。如下:

可以看到已经创建成功了。

2.get /zk-node  获取该节点的内容。如下图:

3.set /zk-node laowang1 修改节点的内容,如下图:

4.delete /zk-node  删除改节点,如下图:

 

值得注意的是:1.ZK的节点可以分为持久化,和临时节点,临时节点:会话断开后,就消失,这个特性最重要的应用就是服务治理。还有一个重要的应用就是分布式锁的排他锁,是独占式的,只有当一个线程释放锁后,其他线程才能进行读写操作。这样就可以使用

ZK节点的临时性了,节点消失后,锁也就释放了。这样其他线程就可以进行读写操作了。

2.ZK的节点还可以存放少量的数据,不要误解可以当数据库使用,ZK还可以监听节点的变化,这样客户端就可以拿到通知了。比如说现在要切换数据源,要改变数据源IP,端口号,这样我们就可以

通过监听节点数据的变化,从而通知其他服务切换数据源,和更改IP和端口等,节点的数据变化了,客户端可以收到通知,可以获取相应的数据进行操作,这样就可以达到前面所提及的配置管理。

3.节点还可以是有顺序的。最重要的应用的就是分布式锁中的共享锁,通过这特性是的先来的编号小,后来的大,如果要读取数据,如果自己的编号最小,那么可以进行读操作,或者比自己编号都小的

操作都是读数据,那么改操作也可以读取数据,如果比自己的编号小前面有进行改数据或者增加数据的操作这时候只能被锁上,等待比自己小的编号修改完数据后,那么此时那个修改数据的临时节点就消失了,

锁也就释放了。这样自己进行读操作了。还有一个重要的应用就是分布式队列,谁的编号小谁即出队。

 

以上这是通过zk命令行弄,开发中不可能这样弄的。以下是在通过在java端通过maven引入一个依赖操作zk.如下图:

下面就开始通过java创建节点,如下图:

结果:

 

现在读取节点中的内容:如下:

输出的结果为:

Connection OK
hjc



判断节点和删除节点,如下图:

结果为:

 

获取节点数据和修改节点的数据如下:

 

监听节点的变化,如下图:

先创建一个节点监听类实现IZkChildListener类,如下图:

再去注册这个监听器,如下图:

先运行,如下图:

 

先在启动其中一个zkclient客户端如下图:注意控制台变化,如下图:

 

可以看到已经监听到节点的变化了。

 

现在我们创建一个节点数据变化的监听器。如下图:

 

现在对数据监听器进行注册,如下图:

结果如下图:

 

好了我们现在再通过命令行来删除,看一下是否还能监控到,如下图:

 

发现控制台根本没有变化,这是因为用java操作的zkclien给我们提供的数据监听器,和命令行客户端操作并不在同一个线程池里。这样数据监听器是监听不到的。
posted @ 2018-01-25 00:25  妮蔻  阅读(...)  评论(...编辑  收藏