前言相信大家对zookeeper都不陌生。许多分布式中间件使用zk来提供分布式一致性协调功能。Dubbo官方推荐使用zk作为注册中心,zk也是hadoop和Hbase的重要组成部分。Zk也出现在其他知名的开源中间件中。有很多童鞋早就知道zk,知道它的基本概念,知道怎么用。但是当面试问到clusterzk之间的选举和数据同步机制时,我陷入了一个盲点。其实很多分布式中间件的选举和同步都和zk类似。在这篇文章中,我将重点介绍zk集群之间的选举和同步机制。ZK集群的部署首先我们来看运行机制的后半部分:集群至少需要三台服务器,官方文档强烈推荐使用奇数台服务器,因为zookeeper通过判断来判断整个服务集群是否可用大多数节点的生存。比如有3个节点,一半是1.5,向上取整就是2。Hangingup2表示整个集群宕机。而如果你用偶数4,如果其中2个死了,那就意味着不是大部分都活下来了,所以他们也会死。所以如果使用4台服务器,在资源使用上是不划算的。配置语法:server.=::节点ID:1~125之间的数字,写入对应服务节点的{dataDir}/myid文件。IP地址:节点的远程IP地址可以相同。生产环境建议使用不同的机器,否则无法达到容错的目的。数据同步端口:主从同步时的数据复制端口。选举端口:主从节点的选举端口。假设现在有3个zookeeper节点,我们要为它写config配置,还要写3份,分别放在不同的服务器上。配置如下:initLimit=10syncLimit=5dataDir=/data/zk_dataclientPort=2181#集群配置server.1=192.168.1.1:2888:3888server.2=192.168.1.2:2888:3888server.3=192.168.1.3:2888:3888dataDir参数指定了一个存放zk数据的目录,里面有一个文件myid,1、2、3分别存放在3台机器上的myid文件中。对应各自的节点ID。3个配置文件配置完成后,分别启动,这样我们的3个节点的集群zookeeper就搭建好了。./bin/zkServer.shstartconf/zoo.cfgZK集群中的角色Zookeeper集群中常见的角色有3种,分别是leader、follower和observer。角色描述leader主节点,也称为leader。用于写入数据,由选举产生。如果宕机,将选举一个新的主节点。follower子节点,也称为follower。用于读取数据。同时,他也是主节点的候选节点,具有投票权。Observer二级子节点,也称为观察者。它用于读取数据。与follower不同的是,它没有投票权,不能被选为主节点。并且在计算集群的可用状态时不会统计观察者。关于observer的配置:在集群配置中添加observer后缀即可,示例如下:server.观察者不会在生产中配置,因为观察者没有投票权。可以这样理解,观察员是临时工,不是正式员工,不能晋升。除此之外,它具有与跟随器相同的功能。什么时候需要用到观察者,因为zk一般是读请求多于写请求。当整个集群压力过大时,我们可以增加几个临时的worker观察者来提升性能。观察者可以在不需要的时候随时被移除。zk连接的时候,一般我们会配置zk的所有节点,用逗号隔开。事实上,可以连接到任何一个或多个集群。只是如果只有一个节点连接,当节点宕机时,我们断开连接。因此,建议配置多个节点进行连接。如何查看zk集群中的角色我们可以使用如下命令查看zk集群中的角色/bin/zkServer.shstatusconf/zoo.cfg我在自己的机器上搭建了一个3节点的伪集群(共享一台机器),配置文件分别命名为zoo1.cfg、zoo2.cfg、zoo3.cfg。使用上面命令的结果是:可以看到节点2是leader,其他都是follower。但是如果按照zoo1.cfg、zoo2.cfg、zoo3.cfg的顺序启动,无论启动多少次,节点2始终是leader,关闭节点2查看角色,会发现该节点3已成为领导者。以上现象都与zookeeper的选举机制有关。ZK集群的选举机制。我们将以三个节点的zk作为一个简单的选举来说明zk会进行多轮投票,直到某个节点的票数大于等于一半以上。3个节点中,一共会进行2轮投票:第一轮,每个节点在启动时都为自己投票,这样zk1、zk2、zk3各有一票。在第二轮中,每个节点投票给一个比自己大的myid,这样zk2在启动的时候再投一票。加上我投给自己的票。一共有2票。2票超过当前节点总数的一半,则终止投票。zk2被选为领导者。有童鞋会问,zk3呢,因为zk2已经选出来了,投票已经终止了。所以zk2不会投票给zk3。当然,这是选比较简单的版本。其实真正的选举需要比较zxid,后面会讲到。什么时候会触发zk选举?一种是启动的时候触发,一种是leader宕机的时候触发。在上面的例子中,如果节点2宕机了,按照规则,leader应该是zk3。ZK集群的数据同步机制。zookeeper的数据同步是为了保证各个节点数据的一致性。大致分为两个过程,一个是客户端正常的数据提交过程,一个是集群中某个节点宕机后的数据恢复。过程。正常的客户端数据提交流程客户端写数据提交流程大致如下:leader收到客户端的写请求,然后同步发送给各个子节点:但是有童鞋造成混淆。client一般连接所有节点,client不知道哪个是leader。的确,客户端会与所有节点建立链接,并发起写请求逐一遍历节点,比如第一次遍历节点1,第二次遍历节点2。等等。如果client刚好连接的节点的角色是leader,那么就按照上面的流程。如果被链接的节点不是leader而是follower,流程如下:如果client选择一个被链接的节点作为follower,follower会将请求转发给当前的leader,然后leader将请求广播给所有Follower,每个节点同步完数据后,会用绿线告诉Leader数据已经同步(但还没有提交)。当Leader收到超过半数的节点ACK确认报文时,则Leader认为可以提交数据,会广播给所有Follower节点,所有节点都可以提交数据。整个同步工作就结束了。然后说下节点宕机后的数据同步过程。当zookeeper集群中的Leader宕机时,会触发新的选举。选举期间,整个集群无法对外提供服务。在选举出新的领导者之前,无法恢复服务。让我们回到3个节点zk1、zk2和zk3的示例,其中z2是领导者,z1和z3是追随者。假设zk2宕机后,触发重新选举。Accordingtotheelectionrules,z3iselectedastheleader.此时整个集群中只调整了z1和z3。如果此时整个集群又创建了一个节点数据,则重启z2。这时候z2的数据肯定比z1和z3的数据更老,那么这时候怎么同步数据呢。Zookeeper由ZXID事务ID确认。ZXID是一个64位的数字,低32位根据数字递增。任何数据变化都会导致低32位数字简单地增加1。高32位是领导者的循环数。WheneveranewLeaderiselected,thenewLeadertakesouttheZXIDfromthelocaltransactionlog,thenparsesoutthecyclenumberoftheupper32bits,adds1,andthenadds1tothelower32bits.全部设置为0。这样可以保证每次选举出新的Leader后,保证ZXID的唯一性,保证递增。查看数据节点ZXID的命令为:首先进入zk客户端命令行./bin/zkCli.sh-server127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183stat加上数据节点namestat/test的执行结果为:可以看到有3个ZXID,每个代表:cZxid:节点创建时的事务IDmZxid:节点最后一次更新时的事务IDpZxid:最新的子节点节点的节点查看创建/更新/删除事务ID的最新ZXID的命令为:echostat|nc127.0.0.12181这条命令需要提前添加到cfg文件中:4lw.commands.whitelist=*,然后重启ZXID这里是当前节点上次交易的ID。如果整个集群数据是一致的,那么所有节点的ZXID应该是一样的。所以zookeeper就是使用这个有序的ZXID来保证各个节点之间数据的一致性。有了之前的问题,如果Leader宕机重启,会把最新的ZXID和当前的Leader进行比较。如果该节点的ZXID小于最新Leader中的ZXID,则同步数据。再来看看ZK中的选举。我们用ZXID的概念来看一下ZK中的选举机制。假设还有一个3节点的集群,zk2是leader。如果此时zk2挂了。zk3被选举为Leader,zk1为Follower。这时候如果更新集群中的一条数据。然后关闭zk1和zk3。然后一一重启zk1、zk2、zk3。Afterstartingatthistime,canzk2stillbeelectedastheLeader?其实这个问题,换句话说:zk节点一个接一个启动的时候,zk1和zk3的数据是最新的,而zk2的数据不是。根据先前的选举规则,ZK2可以成功选举为领导者吗?答案是否定的,最后选出来的是zk1。为什么是这样。因为zk2最新的ZXID不是最新的,所以zk的选举过程会优先选择ZXID大的节点。此时ZXID最大的是zk1和zk3,根据前面提到的选举规则,选举只会在这两个节点发生。在第一轮投票中,只要ZK1获得1票,它就可以达到一半的投票,并且可以成功选举为领导者。最后,zk的选举和同步并不复杂。如果可以尝试在本地搭建3个节点的伪集群,试试上面的case。你应该能够理解整个过程。zk作为一个老牌的一致性协调中间件,在很多面试中也是经常被问到的问题。如果你能看懂本文的核心内容,再遇到此类问题,这就不是你的盲点了。最后,喜欢本文内容的朋友希望点赞、关注、转发。