Winse Blog

走走停停, 熙熙攘攘, 忙忙碌碌, 不知何畏.

Zookeeper节点切换

更新:下面的操作都是基于不停机不停服务的前提下的。如果可以停服务的话,你想怎么折腾就怎么折腾(只要zoo.cfg和myid一致就行)。

收告警邮件实在是收到烦了,zookeeper实例的机器挂掉了,机器一直没人处理。最后最终还是改了告警的脚本(呵呵,等到快出问题的时刻才告警)。

过程中也尝试了添加删除节点,下面是对本次体验的一些记载。

告警的检查脚本帖出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
msg=`$HADOOP_HOME/bin/hdfs getconf -confKey ha.zookeeper.quorum 2>/dev/null`

zks_total=`echo "$msg" | awk 'BEGIN{RS=","; } {print}' | grep -v '^$' `
total_count=`echo "$zks_total" | wc -l `

lost_zks=`echo "$zks_total" |  while read zk  ; do if ! echo mntr | nc ${zk//:/ } | grep zk_server_state >/dev/null ; then echo "$zk " ; fi ; done  `
lost_count=`echo "$lost_zks" | grep -v "^$" | wc -l ` 
lost_zks=`echo $lost_zks `

message="Zookeepers total: $total_count, dead: $lost_count"
if  [[ "$lost_count" != 0 ]]
then
  message="$message;  Dead: $lost_zks"
fi 

if (( $lost_count*2 > $total_count )) ; then
        echo "CRITICAL - $message"
        exit 2
elif (( $total_count/2 == $lost_count )) ; then
        echo "WARNING - $message"
        exit 1
else 
        echo "OK - $message"
        exit 0
fi

zookeeper3.5

zookeeper3.5的版本已经有动态增删节点的功能。

手动割接问题节点

生产的是3.4的,不支持reconfig的命令。这里使用 rolling restarts 手动切换的方式来进行割接,在测试环境通过不同的端口来模拟3台机器:

割接的时刻,最好一台台的加,不然可能会出现数据不一致的情况:https://www.slideshare.net/Hadoop_Summit/dynamic-reconfiguration-of-zookeeper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[hadoop@cu3 zktest]$ mv zoo_sample.cfg zoo1.cfg
[hadoop@cu3 zktest]$ sed -e 's/12181/22181/' -e 's/data1/data2/' zoo1.cfg >zoo2.cfg
[hadoop@cu3 zktest]$ sed -e 's/12181/32181/' -e 's/data1/data3/' zoo1.cfg >zoo3.cfg
[hadoop@cu3 zktest]$ cat zoo3.cfg 
tickTime=2000
initLimit=10
syncLimit=5
#maxClientCnxns=60

dataDir=/home/hadoop/zktest/data3
clientPort=32181

server.1=localhost:13888:13999
server.2=localhost:23888:23999
server.3=localhost:33888:33999

[hadoop@cu3 zktest]$ for i in {1..3} ; do echo $i >data$i/myid ; done 

# 添加两个便利的函数
[hadoop@cu3 zktest]$ function zkstat { 
> for i in {1..4} ; do ( echo "${i}2181 => `cat data$i/zookeeper_server.pid` : `echo mntr | nc localhost ${i}2181 | grep zk_server_state | awk '{print $2}' ` " ) ; done
> }

[hadoop@cu3 zktest]$ function zkstart { 
> for i in "$@" ; do (cd data$i ; ~/zookeeper-3.4.6/bin/zkServer.sh start /home/hadoop/zktest/zoo$i.cfg ) ; done
> }

[hadoop@cu3 zktest]$ zkstart {1..3}

切换时,Leader一直不变

模拟server.1进程down掉,用一个新的server.4代替: 切换的过程中不能停leader!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 配置server.4
[hadoop@cu3 zktest]$ sed -e 's/12181/42181/' -e 's/data1/data4/' zoo1.cfg >zoo4.cfg
[hadoop@cu3 zktest]$ mkdir data4
[hadoop@cu3 zktest]$ echo 4 > data4/myid

# 去掉server.1,添加server.4
[hadoop@cu3 zktest]$ vi zoo4.cfg 
...
server.4=localhost:43888:43999

[hadoop@cu3 zktest]$ zkstat
12181 => 20750 : follower 
22181 => 21037 : leader 
32181 => 21075 : follower 
42181 => 19757 :  

# 停server.1
[hadoop@cu3 zktest]$ kill 20750

# 启动server.4
[hadoop@cu3 zktest]$ zkstart {2..4}
[hadoop@cu3 zktest]$ zkstat 
12181 => 20750 :  
22181 => 21037 : leader 
32181 => 21075 : follower 
42181 => 21246 : follower 

此时server.4是新的配置,server.2和server.3是旧的配置。

# 停server.3,注意这里不能停leader!!
[hadoop@cu3 zktest]$ kill 21075
[hadoop@cu3 zktest]$ zkstat
12181 => 20750 :  
22181 => 21037 : leader 
32181 => 21075 :  
42181 => 21246 : follower 

# server.3的配置:server.1换成server.4
[hadoop@cu3 zktest]$ vi zoo3.cfg 
[hadoop@cu3 zktest]$ zkstart 3
JMX enabled by default
Using config: /home/hadoop/zktest/zoo3.cfg
Starting zookeeper ... STARTED
[hadoop@cu3 zktest]$ zkstat
12181 => 20750 :  
22181 => 21037 : leader 
32181 => 21791 : follower 
42181 => 21246 : follower 

3个server有两个已经是新的配置,现在停掉leader后重新选举也是ok的。

# 最后停leader,修改zoo2.cfg。集群down节点成功切换!!
[hadoop@cu3 zktest]$ zkstat
12181 => 20750 :  
22181 => 22044 : follower 
32181 => 21791 : follower 
42181 => 21246 : leader 

中间停Leader,重新选领导失败

现在再测试下中间过程停leader会是什么效果呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 先zoo4挂掉了,用zoo1来补充。
[hadoop@cu3 zktest]$ zkstat
12181 => 20750 :  
22181 => 22044 : leader 
32181 => 21791 : follower 
42181 => 21246 : 

配置 zoo1: 

# 修改zoo1的配置 和 myid,不能用原来的旧id: Have smaller server identifier, so dropping the connection: (3, 1)
server.5=localhost:13888:13999
server.2=localhost:23888:23999
server.3=localhost:33888:33999

# 此时zoo2,zoo3的配置为:
server.2=localhost:23888:23999
server.3=localhost:33888:33999
server.4=localhost:43888:43999

# 启动zoo1(id=5)
[hadoop@cu3 zktest]$ zkstart 1
[hadoop@cu3 zktest]$ zkstat
12181 => 22439 : follower 
22181 => 22044 : leader 
32181 => 21791 : follower 
42181 => 21246 :  

如果这里停的leader,zoo1收不到大于1/2的投票?
(觉得:只能在配置里面server才会被接受选票,
所以停了zoo2(leader)后,zoo3配置里面的server就只有自己了,zoo3也就拒接服务,然后接着zoo1(id=5)也拒接服务)

[hadoop@cu3 zktest]$ kill 22044
[hadoop@cu3 zktest]$ zkstat
12181 => 22439 :  
22181 => 22044 :  
32181 => 21791 :  
42181 => 21246 :  
[hadoop@cu3 zktest]$ jps -m | grep zktest
21791 QuorumPeerMain /home/hadoop/zktest/zoo3.cfg
22439 QuorumPeerMain /home/hadoop/zktest/zoo1.cfg

服务挂了!!

所以说5台zookeeper还是很有必要的,5台的话挂掉一台,Leader在切换的过程中停掉了其他三台机器也能正常选举出新的Leader。

正常切换后,应用不需要修改。只要zkserver中的一台zk服务器能连接就可以了。但可能监控的需要进行修改,因为原来是监控所有服务的,配置可能需要进行相应的修改。

–END

Comments