臭味相投的朋友们,我在这里:
猿in小站:http://www.yuanin.net
csdn博客:https://blog.csdn.net/jiabeis
简书:https://www.jianshu.com/u/4cb7d664ec4b
微信免费订阅号“猿in”
说明:本文zk为zookeeper缩写。
@[toc]
zk集群原理
ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现。 分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协 调/通知、集群管理、Master 选举、分布式锁和分布式队列 等功能。
集群角色
- Leader (领导)
- Follower (追随者)
- Observer (观察员)
一个 ZooKeeper 集群同一时刻只会有一个 Leader,其他都是 Follower 或 Observer。ZooKeeper 配置很简单,每个节点的配置文件(zoo.cfg)都是一样的,只有 myid 文件不一样。myid 的值必须是 zoo.cfg中server.{数值} 的{数值}部分。
节点读写服务分工
ZooKeeper 集群的所有机器通过一个 Leader 选举过程来选定一台被称为『Leader』 的机器,Leader服务器为客户端提供读和写服务。
Follower 和 Observer 都能提供读服务,不能提供写服务。两者唯一的区别在于, Observer机器不参与 Leader 选举过程,也不参与写操作的『过半写成功』策略,因 此 Observer 可以在不影响写性能的情况下提升集群的读性能。
session
Session 是指客户端会话,在讲解客户端会话之前,我们先来了解下客户端连接。在 ZooKeeper 中,一个客户端连接是指客户端和 ZooKeeper 服务器之间的TCP长连接。
ZooKeeper 对外的服务端口默认是2181,客户端启动时,首先会与服务器建立一个TCP 连接,从第一次连接建立开始,客户端会话的生命周期也开始了,通过这个连接,客户端能够通 过心跳检测和服务器保持有效的会话,也能够向 ZooKeeper 服务器发送请求并接受响应,同 时还能通过该连接接收来自服务器的 Watch 事件通知。
Session 的 SessionTimeout 值用来设置一个客户端会话的超时时间。当由于服务器 压力太大、网络故障或是客户端主动断开连接等各种原因导致客户端连接断开时,只要在 SessionTimeout 规定的时间内能够重新连接上集群中任意一台服务器,那么之前创建的会话 仍然有效。
zookeeper选举
zookeeper选举,分两个阶段
(1)数据恢复阶段
每台服务器在启动前,都会从本地目录找自己所拥有的Zxid(最大事务id),每有一次操作,都是一个事务,每次事务都会递增,事务id越大,事务越新
(2)选举阶段
每台zk服务器都会提交一个选举协议,协议中的内容:
①自己的zxid(事务id)
②选举id(myid文件里的数字)
③逻辑时钟值(和选举轮数有关),作用是确保每台zk服务器处于同一轮选举中
④状态-(Looking)选举状态,Leader,Follower,Observer
(3)选举PK原则
先比较Zxid,谁大谁当Leader,如果Zxid比较不出来,再比较选举ID,谁大谁当Leader(前提是要满足过半机制)
注意:zookeeper有一个过半存活机制,比如,三台服务器,挂掉一个可以,挂掉两个不能工作
(4)Leader选举成功之后
首先要做的就是数据同步,目的是确保zk集群的数据一致性,一是可以保证当Leader挂掉之后,其他Follower可以顶替工作,此外要确保客户端无论从哪个zk服务器获取数据都是一致的,这种实现数据一致性的过程称为原子广播(Atomic Brodcast)
(5)过半性
Zookeeper集群必须有半数以上的机器存活才能正常工作,因为只有满足过半数,才能满足选举机制选出Leader,因为只有过半,在做事务决议时,事务才能更新,所以一般来说,zookeeper集群的数量最好是奇数个。
Zookeeper迁移(扩容/缩容)
在迁移前有必要了解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配置如下:
# 省略其他配置
dataDir=/data
server.1=node1:2888:3888
server.2=node2:2888:3888
server.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,内容如下:
# 省略其他配置 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,例如以下命令:
./zkServer.sh status
可以看到Mode表示该节点的角色为leader。依次检查每一个节点,如果没有响应,或者出现多个leader,需要还原整个集群!
步骤2:新增节点5
-
在
/data
目录创建mid文件,内容为5 -
配置zoo.cfg,内容如下:
# 省略其他配置 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:
$ 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,内容如下:
# 省略其他配置 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:
步骤4:更新节点4
- 修改节点4的配置如下:
# 省略其他配置 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.
步骤5:更新节点5
同步骤4
步骤6:更新老集群节点1
-
修改节点1的配置如下:
//省略其他配置
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 -
重启节点1的zookeeper:
{zookeeperDir}/bin/zkServer.sh restart
-
检查所有节点是否提供服务,且集群中只有一个leader:
步骤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的配置,并且重启,配置如下:
//省略其他配置
dataDir=/data
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
重启后检查所有节点是否提供服务,且集群中只有一个leader。
ps:这时候如果没有读写zookeeper操作,leader将变成node5,因为node6节点重启的时候,集群重新选举,node5的myid最大
步骤10.2:下线zookeeper老集群中的节点2
关闭node2: {zookeeperDir}/bin/zkServer.sh stop
依次修改node3,4,5,6的配置,并且重启,配置如下:
//省略其他配置
dataDir=/data
server.3=node3:2888:3888
server.4=node4:2888:3888
server.5=node5:2888:3888
server.6=node6:2888:3888
重启后检查所有节点是否提供服务,且集群中只有一个leader。
ps:这时候如果没有读写zookeeper操作,leader将重新变成node6
步骤10.3:下线zookeeper老集群中的节点3
关闭node3: {zookeeperDir}/bin/zkServer.sh stop
依次修改node4,5,6的配置,并且重启,配置如下:
# 省略其他配置
dataDir=/data
server.4=node4:2888:3888
server.5=node5:2888:3888
server.6=node6:2888:3888
重启后检查所有节点是否提供服务,且集群中只有一个leader。
ps:这时候如果没有读写zookeeper操作,node5将成为最终的leader
迁移总结说明
(1)以前应用服务的zk配置可以不改(只要配置里有一个zk节点的地址,如果全部节点都迁移了,可能也不需要改,但是要验证),下次应用服务要重新配置新的集群zk链接串。
(2)dubbo-admin和monitor可以不重新启动(只要配置里有一个zk节点的地址,如果全部节点都迁移了,可能也不需要改,但是要验证),但是改配置文件,下次启动更健壮。
参考
https://blog.51cto.com/536410/2398911
https://www.cnblogs.com/tchroot/p/9573336.html
https://blog.csdn.net/szl13722587073/article/details/79180780
注意:本文归作者所有,未经作者允许,不得转载