在zk集群中,选举是很重要的一个步骤,zk选举算法以fast paxos为基础,在《从Paxos到Zookeeper 分布式一致性原理与实践 》一书中,很详细的做了讲解。
myid:zk搭建集群时,需要为每个zk服务器配置全局唯一的myid
zxid:ZooKeeper状态的每一次改变, 都对应着一个递增的Transaction id
, 该id称为zxid. 由于zxid的递增性质, 如果zxid1小于zxid2, 那么zxid1肯定先于zxid2发生. 创建任意节点, 或者更新任意节点的数据, 或者删除任意节点, 都会导致Zookeeper状态发生改变, 从而导致zxid的值增加。
选举规则:1、zxid大的做为leader
2、zxid相同,myid大的做为leader
3、只要超过半数节点选票一致,所选出的zk就做为leader。如:节点数量5,超过半数节点数量为(5/2)+ 1 = 3。
选举条件:1、集群服务器初次启动。
2、集群工作时,leader宕机。
选举时发送的选票内容包括myid 和 zxid,记为(myid,zxid)。
假设集群环境中有5台zk服务器,分别是server1,server2,server3,server4,server5,搭建集群时,每个服务器会配置myid,server1的myid为1,server2的myid为2,server3的myid为3,server4的myid为4,server5的myid为5。
刚搭建好集群时,所有zk的zxid都为0,此时全部启动zk。
集群初次启动:
1、每台服务器首先用自己myid和zxid做为选票信息,发送给集群中的机器,server1服务器发送(1,0),server2服务器发送(2,0),server3服务器发送(3,0),server4服务器发送(4,0),server5服务器发送(5,0)。
2、每台服务器会收到其他服务器的投票信息(myid,zxid),然后依次进行PK,比如server1会收到(2,0),(3,0),(4,0),(5,0)的选票,然后跟自己的(1,0)做PK,按照选举规则,先判断zxid(这里都是0),zxid相同,所以再比较myid哪个大,这里server5的myid最大,所以server1就更新自己的选票,将(5,0)再次发出。
3、其他服务器,依次做步骤2中的操作,都将自己的选票更新为(5,0),再次发送。因为server5的选票本身就是(5,0),所以不需要更新,可以直接发送。
4、经过步骤3,现在所有的服务器节点选票都是(5,0),满足超过半数选票一致,所以就将server5作为本次选举的leader。
根据“超过半数同意”这个规则,实际上初次启动集群中的5台zk服务器时,只需要启动到第三台,就可能已经可以选出leader了(这取决于leader选举的速度 和 第4台zk启动的速度)。剩下的2台,发现集群中有leader了,就会将自己作为follower节点,跟leader进行数据同步。
leader宕机:
在集群工作时,服务器节点的zxid有可能都不相同,比如server1的zxid为9,server2的zxid为9,server3的zxid为10,server4的zxid为8,server5的zxid为8。其中server3为当前leader。
1、server3宕机了,剩下的server1,server2,server4,server5重新选举,各自发送自己的选票,(1,9),(2,9),(4,8),(5,8)
2、server1接收到(2,9),(4,8),(5,8)的选票,和自己的选票PK,发现(4,8)和(5,8)的zxid比自己小,但是(2,9)的zxid和自己相同,myid比自己大,此时server1将选票更新为(2,9),然后再次发出。
3、其他服务器接收到选票,进行PK后,都将自己的更新为(2,9)发出。
4、新的leader就产生了,为server2服务器。
注意1:为什么zk集群需要至少3台服务器?
因为(3/2) + 1 = 2(超过半数的最小节点数量),3台服务器,leader挂掉后,剩余两台还是可以选出leader来的。如果集群中只有2台服务器,依然可以选出leader,因为(2/1) + 1 = 2,但如果此时leader挂了,就选不出leader了,集群就不可用了。
注意2:为什么zk集群节点要奇数?
因为如果是偶数,会浪费一台服务器。假如集群一有5台服务器,集群二有6台服务器。集群一超过半数的最小节点数为:5/2 + 1 = 3,集群二超过半数的最小节点数为:6/2 + 1 = 4,也就是说集群一和集群二,都只允许挂掉2台服务器,如果挂掉3台,集群都不可用。虽然集群二可以更多的缓解读压力,但是 容灾能力和 集群一相同,也就没必要多出一台服务器了吧。