前言
zookeeper置信大家都不生疏,很多分布式中间件都利用zk来提供分布式一致性协调的个性。dubbo官网举荐应用zk作为注册核心,zk也是hadoop和Hbase的重要组件。其余出名的开源中间件中也都呈现了zk的身影。
有很多童鞋意识zk很久了,晓得其根本理念,晓得如何应用。但当面试时问到集群zk之间的选举和数据同步机制时,就陷入了盲区。
其实很多的分布式中间件的选举和同步,都和zk有殊途同归之妙。这篇文章我就来重点聊下对于zk集群之间的选举和同步机制。
ZK集群的部署
首先咱们来看下半数运行机制:
集群至多须要三台服务器,且官网文档强烈建议应用奇数个服务器,因为zookeeper是通过判断大多数节点的的存活来判断整个服务集群是否可用的,比方3个节点,它的一半是1.5,向上取整就是2。挂掉了2个就是示意整个集群挂掉。而用偶数4个的话,挂掉2个也示意不是大部分存活,因而也会挂掉。所以用4台服务器的话 ,从应用资源上来说,并不划算。
配置语法:
server.<节点ID>=<IP>:<数据同步端口>:<选举端口>
- 节点ID:为1到125之间的数字,写到对应服务节点的{dataDir}/myid文件中。
- IP地址:节点的近程IP地址,能够雷同,生产环境倡议用不同的机器,否则无奈达到容错的目标。
- 数据同步端口:主从同步时数据复制端口。
- 选举端口:主从节点选举端口。
假如当初有3个zookeeper节点,咱们要为其编写config配置,也要编写3份,别离放在不同的服务器上,其配置如下:
<code class="properties">initLimit=10 syncLimit=5 dataDir=/data/zk_data clientPort=2181 # 集群配置 server.1=192.168.1.1:2888:3888 server.2=192.168.1.2:2888:3888 server.3=192.168.1.3:2888:3888
其中dataDir参数指定的是一个目录,用来寄存zk的数据,外面有个文件myid,3台机器上myid文件外面别离寄存1,2,3。对应各自节点ID。
配置好3个配置文件后,别离启动,这样咱们一个3个节点的集群zookeeper就搭建好了。
<code class="bash">./bin/zkServer.sh start conf/zoo.cfg
ZK集群中的角色
zookeeper集群中公共有三种角色,别离是leader
,follower
,observer
。
角色 | 形容 |
---|---|
leader | 主节点,又名领导者。用于写入数据,通过选举产生,如果宕机将会选举新的主节点。 |
follower | 子节点,又名追随者。用于实现数据的读取。同时他也是主节点的备选节点,并领有投票权。 |
observer | 次级子节点,又名观察者。用于读取数据,与follower区别在于没有投票权,不能被选为主节点。并且在计算集群可用状态时不会将observer计算入内。 |
对于observer的配置:
只有在集群配置中加上observer后缀即可,示例如下:
server.3=127.0.0.1:2883:3883:observer
其中leader只有一个,剩下的都是follower和observer,然而咱们个别生产上不会配置observer,因为observer并没有选举权,能够了解为observer是一个临时工,不是正式员工,没法取得降职。除此之外,它和follower的性能是一样的。
什么时候须要用到observer呢,因为zk个别读的申请会大于写。当整个集群压力过大时,咱们能够减少几个临时工observer来取得性能的晋升。在不须要的时候的时候,能够随时撤掉observer。
zk进行连贯时,个别咱们都会把zk所有的节点都配置下来,用逗号分隔。其实连贯集群中的任意一个或者多个都是能够的。只是如果只连一个节点,当这个节点宕机的时候,咱们就断开了连贯。所以还是举荐配置多个节点进行连贯。
如何查看ZK集群中的角色
咱们能够利用以下命令来查看zk集群中的角色
./bin/zkServer.sh status conf/zoo.cfg
我在本人机器上搭建了3个节点的伪集群(共用一台机器),配置文件别离命名为zoo1.cfg,zoo2.cfg,zoo3.cfg。应用以上命令查看的后果为:
能够看到,其中节点2为leader,其余的为follower。然而如果你依照zoo1.cfg,zoo2.cfg,zoo3.cfg的程序启动,无论你启动多少遍,节点2总是leader,而这时如果把节点2关掉,进行查看角色,发现节点3成了leader。
以上这些景象都和zookeeper的选举机制无关
ZK集群的选举机制
咱们就拿3个节点的zk作一个简略选举的阐明
zk会进行多轮的投票,直到某一个节点的票数大于或等于半数以上,在3个节点中,总共会进行2轮的投票:
- 第一轮,每个节点启动时投票给本人,那这样zk1,zk2,zk3各有一票。
- 第二轮,每个节点投票给大于本人myid,那这样zk2启动时又取得一票。加上本人给本人投的那一票。总共有2票。2票大于了以后节点总数的半数,所以投票终止。zk2入选leader。
有的童鞋会问,zk3呢,因为zk2曾经入选了,投票终止了。所以zk2也不会投票给zk3了。
当然这是一个比较简单版的选举,其实真正的选举还要比拟zxid,这个前面会讲到。
zk选举什么时候会被触发呢?一是启动时会被触发,二是leader宕机时会被触发。下面的例子中,如果节点2宕机,依据规定,那取得leader的就应该是zk3了。
ZK集群的数据同步机制
zookeeper的数据同步是为了保障每个节点的数据一致性,大抵分为2个流程,一个是失常的客户端数据提交流程,二是集群中某个节点宕机后数据恢复流程。
失常客户端数据提交流程
客户端写入数据提交流程大抵为:leader承受到客户端的写申请,而后同步给各个子节点:
然而有童鞋就产生纳闷了,客户端个别连贯的是所有节点,客户端并不知道哪个是leader呀。
确实,客户端会和所有的节点建设链接,并且发动写入申请是挨个遍历节点进行的,比方第一次是节点1,第二次是节点2。以此类推。
如果客户端正好链接的节点的角色是leader,那就依照下面的流程走。那如果链接的节点不是leader,是follower呢,则有以下流程:
如果Client抉择链接的节点是Follower的话,这个Follower会把申请转给以后Leader,而后Leader会走蓝色的线把申请播送给所有的Follower,每个节点同步完数据后会走绿色的线通知Leader数据曾经同步实现(然而还未提交),当Leader收到半数以上的节点ACK确认音讯后,那么Leader就认为这个数据能够提交了,会播送给所有的Follower节点,所有的节点就能够提交数据。整个同步工作就完结了。
那咱们再来说说节点宕机后的数据同步流程
当zookeeper集群中的Leader宕机后,会触发新的选举,选举期间,整个集群是没法对外提供服务的。直到选出新的Leader之后,能力从新提供服务。
咱们从新回到3个节点的例子,zk1,zk2,zk3,其中z2为Leader,z1,z3为Follower,假如zk2宕机后,触发了从新选举,依照选举规定,z3入选Leader。这时整个集群只整下z1和z3,如果这时整个集群又创立了一个节点数据,接着z2重启。这时z2的数据必定比z1和z3要旧,那这时该如何同步数据呢。
zookeeper是通过ZXID事务ID来确认的,ZXID是一个长度为64位的数字,其中低32位是依照数字来递增,任何数据的变更都会导致低32位数字简略加1。高32位是leader周期编号,每当选举出一个新的Leader时,新的Leader就从本地事务日志中取出ZXID,而后解析出高32位的周期编号,进行加1,再将低32位的全副设置为0。这样就保障了每次选举新的Leader后,保障了ZXID的唯一性而且是保障递增的。
查看某个数据节点的ZXID的命令为:
<code class="bash">先进入zk client命令行 ./bin/zkCli.sh -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183 stat加上数据节点名称 stat /test
执行后果为:
能够看到,有3个ZXID,这3个ZXID各自代表:
cZxid:该节点创立时的事务ID
mZxid:该节点最近一次更新时的事务ID
pZxid:该节点的子节点的最新一次创立/更新/删除的事务ID
查看节点最新ZXID的命令为:
echo stat|nc 127.0.0.1 2181 这个命令需提前在cfg文件后追加:4lw.commands.whitelist=*,而后重启
这里的ZXID就是以后节点最初一次事务的ID。
如果整个集群数据为统一的,那么所有节点的ZXID应该一样。所以zookeeper就通过这个有序的ZXID来确保各个节点之间的数据的一致性,带着之前的问题,如果Leader宕机之后,再重启后,会去和目前的Leader去比拟最新的ZXID,如果节点的ZXID比最新Leader里的ZXID要小,那么就会去同步数据。
再看ZK中的选举
咱们带着ZXID的概念再来看ZK中的选举机制。
假如还是有一个3个节点的集群,zk2为Leader,这时候如果zk2挂了。zk3入选Leader,zk1为Follower。这时候如果更新集群中的一个数据。而后把zk1和zk3都敞开。而后挨个再重启zk1,zk2,zk3。这时候启动后,zk2还能入选为Leader吗?
其实这个问题,换句话说就是:在挨个启动zk节点的时候,zk1和zk3的数据为最新,而zk2的数据不是最新的,依照之前的选举规定的话,zk2是否能顺利入选Leader?
答案为否,最初入选的为zk1。
这是为什么呢。
因为zk2的最新ZXID曾经不是最新了,zk的选举过程会优先思考ZXID大的节点。这时ZXID最大的有zk1和zk3,选举只会在这2个节点中产生,依据之前说的选举规定。在第一轮投票的时候,zk1只有取得1票,就能达到半数了,就能顺利入选为Leader了。
最初
其实zk的选举和同步并不简单,如果能试着在本地去搭建3个节点的伪集群,去试着跑一下下面的案例。应该就能明确整个过程。zk作为老牌的一致性协调中间件,也是诸多面试的频次很高的问点。如果你能了解本篇的核心内容,再次碰到这类问题的时候,这将不会是你的盲区。最初,喜爱本篇内容的敌人心愿点赞,关注,转发。