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 | # 省略其他配置 |
使用命令: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
2
3
4
5
6# 省略其他配置
dataDir=/data
server.1=node1:2888:3888
server.2=node2:2888:3888
server.3=node3:2888:3888
server.4=node4:2888:3888啓動zookeeper:
{zookeeperDir}/bin/zkServer.sh start
檢查所有節點是否提供服務,且集羣中只有一個leader,例如以下命令:
可以看到Mode表示該節點的角色爲leader。依次檢查每一個節點,如果沒有響應,或者出現多個leader,需要還原整個集羣!
步驟2:新增節點5
在
/data
目錄創建mid文件,內容爲5配置zoo.cfg,內容如下:
1
2
3
4
5
6
7# 省略其他配置
dataDir=/data
server.1=node1:2888:3888
server.2=node2:2888:3888
server.3=node3:2888:3888
server.4=node4:2888:3888
server.5=node5:2888:3888啓動zookeeper:
{zookeeperDir}/bin/zkServer.sh start
檢查所有節點是否提供服務,且集羣中只有一個leader:
1
2
3
4
5
6
7
8
9
10$ 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
2
3
4
5
6
7
8# 省略其他配置
dataDir=/data
server.1=node1:2888:3888
server.2=node2:2888:3888
server.3=node3:2888:3888
server.4=node4:2888:3888
server.5=node5:2888:3888
server.6=node6:2888:3888啓動zookeeper:
{zookeeperDir}/bin/zkServer.sh start
檢查所有節點是否提供服務,且集羣中只有一個leader:
1
2
3
4
5
6
7
8
9
10
11
12$ 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
2
3
4
5
6
7
8# 省略其他配置
dataDir=/data
server.1=node1:2888:3888
server.2=node2:2888:3888
server.3=node3:2888:3888
server.4=node4:2888:3888
server.5=node5:2888:3888
server.6=node6:2888:3888重啓節點4的zookeeper:
{zookeeperDir}/bin/zkServer.sh restart
檢查所有節點是否提供服務,且集羣中只有一個leader:
1
2
3
4
5
6
7
8
9
10
11
12$ 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
2
3
4
5
6
7
8# 省略其他配置
dataDir=/data
server.1=node1:2888:3888
server.2=node2:2888:3888
server.3=node3:2888:3888
server.4=node4:2888:3888
server.5=node5:2888:3888
server.6=node6:2888:3888重啓節點4的zookeeper:
{zookeeperDir}/bin/zkServer.sh restart
檢查所有節點是否提供服務,且集羣中只有一個leader:
1
2
3
4
5
6
7
8
9
10
11
12$ 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 | # 省略其他配置 |
重啓後檢查所有節點是否提供服務,且集羣中只有一個leader。
ps:這時候如果沒有讀寫zookeeper操作,leader將變成node5,因爲node6節點重啓的時候,集羣重新選舉,node5的myid最大
步驟10.2:下線zookeeper老集羣中的節點2
關閉node2: {zookeeperDir}/bin/zkServer.sh stop
依次修改node3,4,5,6的配置,並且重啓,配置如下:
1 | # 省略其他配置 |
重啓後檢查所有節點是否提供服務,且集羣中只有一個leader。
ps:這時候如果沒有讀寫zookeeper操作,leader將重新變成node6
步驟10.3:下線zookeeper老集羣中的節點3
關閉node3: {zookeeperDir}/bin/zkServer.sh stop
依次修改node4,5,6的配置,並且重啓,配置如下:
1 | # 省略其他配置 |
重啓後檢查所有節點是否提供服務,且集羣中只有一個leader。
ps:這時候如果沒有讀寫zookeeper操作,node5將成爲最終的leader