背景
由于一些历史原因,目前zookeeper集群(3个节点)和elasticsearch、hadoop部署在一起,导致几个组件相互影响,性能也逐渐下降。甚至出现某个组件异常(例如oom)导致了其他组件不可用。
由于大量项目使用dubbo且依赖zookeeper作为注册中心,zookeeper的不稳定可能是致命的,所以计划先将zookeeper迁出到3台独立的节点,在此记录下迁移方案。
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 url指向新集群的3个节点,停掉老zookeeper集群。
相当于先扩容zookeeper,然后缩容zookeeper…
迁移步骤
原有zookeeper集群(server1、server2、server3)zoo.cfg配置如下:
|
|
使用命令:echo srvr | nc node{?} 2181
检查谁是leader({?}依次替换为1、2、3)
ps:也可以用echo stat | nc node{?} 2181
显示更详细信息
这里假设leader为node2.(按照正常情况,leader也理应是node2)
步骤1:新增节点4
- 在
/data
目录创建mid文件,内容为4 配置zoo.cfg,内容如下:
123456# 省略其他配置dataDir=/dataserver.1=node1:3181:4181server.2=node2:3181:4181server.3=node3:3181:4181server.4=node4:3181:4181启动zookeeper:
{zookeeperDir}/bin/zkServer.sh start
检查所有节点是否提供服务,且集群中只有一个leader,例如以下命令:
12345678910$ echo srvr | nc node1 2181Zookeeper version: 3.4.5-cdh5.7.0--1, built on 03/23/2016 18:30 GMTLatency min/avg/max: 0/6/190Received: 16002Sent: 19874Connections: 1Outstanding: 0Zxid: 0x3b00004872Mode: leaderNode count: 334
可以看到Mode表示该节点的角色为leader。依次检查每一个节点,如果没有响应,或者出现多个leader,需要还原整个集群!
步骤2:新增节点5
- 在
/data
目录创建mid文件,内容为5 配置zoo.cfg,内容如下:
1234567# 省略其他配置dataDir=/dataserver.1=node1:3181:4181server.2=node2:3181:4181server.3=node3:3181:4181server.4=node4:3181:4181server.5=node5:3181:4181启动zookeeper:
{zookeeperDir}/bin/zkServer.sh start
检查所有节点是否提供服务,且集群中只有一个leader:
12345678910$ echo srvr | nc node1 2181...$ echo srvr | nc node2 2181...$ echo srvr | nc node3 2181...$ echo srvr | nc node4 2181...$ echo srvr | nc node5 2181...
步骤3:新增节点6
- 在
/data
目录创建mid文件,内容为6 配置zoo.cfg,内容如下:
12345678# 省略其他配置dataDir=/dataserver.1=node1:3181:4181server.2=node2:3181:4181server.3=node3:3181:4181server.4=node4:3181:4181server.5=node5:3181:4181server.6=node6:3181:4181启动zookeeper:
{zookeeperDir}/bin/zkServer.sh start
检查所有节点是否提供服务,且集群中只有一个leader:
123456789101112$ echo srvr | nc node1 2181...$ echo srvr | nc node2 2181...$ echo srvr | nc node3 2181...$ echo srvr | nc node4 2181...$ echo srvr | nc node5 2181...$ echo srvr | nc node6 2181...
步骤4:更新节点4
修改节点4的配置如下:
12345678# 省略其他配置dataDir=/dataserver.1=node1:3181:4181server.2=node2:3181:4181server.3=node3:3181:4181server.4=node4:3181:4181server.5=node5:3181:4181server.6=node6:3181:4181重启节点4的zookeeper:
{zookeeperDir}/bin/zkServer.sh restart
检查所有节点是否提供服务,且集群中只有一个leader:
123456789101112$ echo srvr | nc node1 2181...$ echo srvr | nc node2 2181...$ echo srvr | nc node3 2181...$ echo srvr | nc node4 2181...$ echo srvr | nc node5 2181...$ echo srvr | nc node6 2181...
步骤5:更新节点5
同步骤4
步骤6:更新老集群节点1
修改节点1的配置如下:
12345678# 省略其他配置dataDir=/dataserver.1=node1:3181:4181server.2=node2:3181:4181server.3=node3:3181:4181server.4=node4:3181:4181server.5=node5:3181:4181server.6=node6:3181:4181重启节点4的zookeeper:
{zookeeperDir}/bin/zkServer.sh restart
检查所有节点是否提供服务,且集群中只有一个leader:
123456789101112$ echo srvr | nc node1 2181...$ echo srvr | nc node2 2181...$ echo srvr | nc node3 2181...$ echo srvr | nc node4 2181...$ echo srvr | nc node5 2181...$ echo srvr | nc node6 2181...
步骤7:更新老集群节点3
同步骤6
步骤8:更新老集群节点2
最后更新leader节点:node2,同步骤6
ps:这时候如果没有读写zookeeper操作,集群的leader将变为节点6(因为节点6的myid最大)
步骤9:将原有zookeeper的url指向新的节点
运维修改nginx配置,zookeeper url(例如pro1.zookeeper.so、pro2.zookeeper.so、pro3.zookeeper.so)指向node4,node5,node6
相关业务系统重启(避免cdh缓存)
步骤10:老zookeeper集群下线
这一步需要等待所有的业务系统都重启之后。
这时候还是得一台一台关闭(下线),因为假如同时关闭node1和node2,那当重启node3的时候集群将不可用(没有超过集群半数的节点存活)
步骤10.1:下线zookeeper老集群中的节点1
关闭node1: {zookeeperDir}/bin/zkServer.sh stop
依次修改node2,3,4,5,6的配置,并且重启,配置如下:
|
|
重启后检查所有节点是否提供服务,且集群中只有一个leader。
ps:这时候如果没有读写zookeeper操作,leader将变成node5,因为node6节点重启的时候,集群重新选举,node5的myid最大
步骤10.2:下线zookeeper老集群中的节点2
关闭node2: {zookeeperDir}/bin/zkServer.sh stop
依次修改node3,4,5,6的配置,并且重启,配置如下:
|
|
重启后检查所有节点是否提供服务,且集群中只有一个leader。
ps:这时候如果没有读写zookeeper操作,leader将重新变成node6
步骤10.3:下线zookeeper老集群中的节点3
关闭node3: {zookeeperDir}/bin/zkServer.sh stop
依次修改node4,5,6的配置,并且重启,配置如下:
|
|
重启后检查所有节点是否提供服务,且集群中只有一个leader。
ps:这时候如果没有读写zookeeper操作,node5将成为最终的leader
结束。