zookeeper选举原理
在迁移前有必要了解zookeeper的选举原理,以便更科学的迁移。
快速选举FastLeaderElection
zookeeper默认使用快速选举,在此重点了解快速选举:
向集群中的其他zookeeper建立连接,并且只有myid比对方大的连接才会被接受(也就是每2台只会有1个连接,避免连接浪费)
每台zookeeper默认先投自己,然后向集群广播自己的选票
收到对方的选票时,依次比较epoch(选举轮数)、zxid(事务id)、myid,较大者胜出,更新选票并广播
如果收到的选票中有某个节点超过集群半数,则胜出当选为leader,其他节点为follower
注意事项
zookeeper集群的数量应为奇数:
因为根据paxos理论,只有集群中超过半数的节点还存活才能保证集群的一致性。假如目前集群有5个节点,我们最多允许2个节点不可用,因为3>5\2。当集群扩容到6个节点的时候,我们仍然只能最多允许2个节点不可用,到3个节点不可用时,将不满足paxos理论,因为3>6\2不成立。也就是说当集群节点数n为偶数时,其可用性与n-1是一样的,那我们何必多浪费一台机器呢?
由于zookeeper只允许mid大的节点连接到mid小的节点,我们启动zookeeper的顺序应该按照myid小的到myid大的,最后再启动leader节点!
迁移目标
迁移过程中要保证原zookeeper集群还是能提供服务,新zookeeper集群同步老集群的数据,将zookeeper 域名指向新集群的3个节点,停掉老zookeeper集群。
相当于先扩容zookeeper,然后缩容zookeeper…
迁移步骤
原有zookeeper集群(server1、server2、server3)zoo.cfg配置如下:
1 2345 | # 省略其他配置 dataDir=/dataserver.1=node1:2888:3888server.2=node2:2888:3888server.3=node3:2888:3888 |
使用命令:echo srvr | nc HOSTNAME 2181
检查谁是leader({?}依次替换为1、2、3)
ps:也可以用echo stat | nc HOSTNAME 2181
显示更详细信息
这里假设leader为node2.(按照正常情况,leader也理应是node2)
步骤1:新增节点4
在
/data
目录创建mid文件,内容为4配置zoo.cfg,内容如下:
1
23456# 省略其他配置
dataDir=/dataserver.1=node1:2888:3888server.2=node2:2888:3888server.3=node3:2888:3888server.4=node4:2888:3888启动zookeeper:
{zookeeperDir}/bin/zkServer.sh start
检查所有节点是否提供服务,且集群中只有一个leader,例如以下命令:
可以看到Mode表示该节点的角色为leader。依次检查每一个节点,如果没有响应,或者出现多个leader,需要还原整个集群!
步骤2:新增节点5
在
/data
目录创建mid文件,内容为5配置zoo.cfg,内容如下:
1
234567# 省略其他配置
dataDir=/dataserver.1=node1:2888:3888server.2=node2:2888:3888server.3=node3:2888:3888server.4=node4:2888:3888server.5=node5:2888:3888启动zookeeper:
{zookeeperDir}/bin/zkServer.sh start
检查所有节点是否提供服务,且集群中只有一个leader:
1
2345678910$ echo srvr | nc HOSTNAME 2181
...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...
步骤3:新增节点6
在
/data
目录创建mid文件,内容为6配置zoo.cfg,内容如下:
1
2345678# 省略其他配置
dataDir=/dataserver.1=node1:2888:3888server.2=node2:2888:3888server.3=node3:2888:3888server.4=node4:2888:3888server.5=node5:2888:3888server.6=node6:2888:3888启动zookeeper:
{zookeeperDir}/bin/zkServer.sh start
检查所有节点是否提供服务,且集群中只有一个leader:
1
23456789101112$ echo srvr | nc HOSTNAME 2181
...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...
步骤4:更新节点4
修改节点4的配置如下:
1
2345678# 省略其他配置
dataDir=/dataserver.1=node1:2888:3888server.2=node2:2888:3888server.3=node3:2888:3888server.4=node4:2888:3888server.5=node5:2888:3888server.6=node6:2888:3888重启节点4的zookeeper:
{zookeeperDir}/bin/zkServer.sh restart
检查所有节点是否提供服务,且集群中只有一个leader:
1
23456789101112$ echo srvr | nc HOSTNAME 2181
...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...
步骤5:更新节点5
同步骤4
步骤6:更新老集群节点1
修改节点1的配置如下:
1
2345678# 省略其他配置
dataDir=/dataserver.1=node1:2888:3888server.2=node2:2888:3888server.3=node3:2888:3888server.4=node4:2888:3888server.5=node5:2888:3888server.6=node6:2888:3888重启节点4的zookeeper:
{zookeeperDir}/bin/zkServer.sh restart
检查所有节点是否提供服务,且集群中只有一个leader:
1
23456789101112$ echo srvr | nc HOSTNAME 2181
...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...$ echo srvr | nc HOSTNAME 2181...
步骤7:更新老集群节点3
同步骤6
步骤8:更新老集群节点2
最后更新leader节点:node2,同步骤6
ps:这时候如果没有读写zookeeper操作,集群的leader将变为节点6(因为节点6的myid最大)
步骤9:将原有zookeeper的url指向新的节点
修改域名解析,将zookeeper解析到新的3个节点上 (例如test1.zookeeper.com、test2.zookeeper.com、test3.zookeeper.com)指向node4,node5,node6
相关业务系统重启(避免缓存)
步骤10:老zookeeper集群下线
这一步需要等待所有的业务系统都重启之后。
这时候还是得一台一台关闭(下线),因为假如同时关闭HOSTNAME和node2,那当重启node3的时候集群将不可用(没有超过集群半数的节点存活)
步骤10.1:下线zookeeper老集群中的节点1
关闭HOSTNAME: {zookeeperDir}/bin/zkServer.sh stop
依次修改node2,3,4,5,6的配置,并且重启,配置如下:
1 234567 | # 省略其他配置 dataDir=/dataserver.2=node2:2888:3888server.3=node3:2888:3888server.4=node4:2888:3888server.5=node5:2888:3888server.6=node6:2888:3888 |
重启后检查所有节点是否提供服务,且集群中只有一个leader。
ps:这时候如果没有读写zookeeper操作,leader将变成node5,因为node6节点重启的时候,集群重新选举,node5的myid最大
步骤10.2:下线zookeeper老集群中的节点2
关闭node2: {zookeeperDir}/bin/zkServer.sh stop
依次修改node3,4,5,6的配置,并且重启,配置如下:
1 23456 | # 省略其他配置 dataDir=/dataserver.3=node3:2888:3888server.4=node4:2888:3888server.5=node5:2888:3888server.6=node6:2888:3888 |
重启后检查所有节点是否提供服务,且集群中只有一个leader。
ps:这时候如果没有读写zookeeper操作,leader将重新变成node6
步骤10.3:下线zookeeper老集群中的节点3
关闭node3: {zookeeperDir}/bin/zkServer.sh stop
依次修改node4,5,6的配置,并且重启,配置如下:
1 2345 | # 省略其他配置 dataDir=/dataserver.4=node4:2888:3888server.5=node5:2888:3888server.6=node6:2888:3888 |
重启后检查所有节点是否提供服务,且集群中只有一个leader。
ps:这时候如果没有读写zookeeper操作,node5将成为最终的leader