zookeeper分布式系统中面临的很多问题, 如分布式锁,统一的命名服务,配置中心,集群的管理Leader的选举等
环境准备#
分布式系统中各个节点之间通信,Zookeeper保证了这个过程中 数据的唯一性,安全可靠
- 修改配置文件
将/conf/zoo_sample.cfg 修改成 zoo.cfg
配置文件解读
# zookeeper 服务器和客户端之间维持心跳的时间间隔,即每隔ticktime发送一个心跳包,单位是毫秒 # zookeeper 中session过期的时间是 ticktime*2 tickTime=2000 # Leader 允许Follower在initLimit时间内完成从Leader身上同步全部数据的工作, 随机集群的不断扩大,Follower从Leader上同步数据的时间就会变成,此时有必要,默认是0 initLimit=10 # Leader会和集群中的其他机器进行通信,在syncLimit时间内,都没有从Follower上获取返回数据,就认为这个节点挂了 syncLimit=5 # 存储快照文件的目录,默认情况下事务日志也在这里了,下面单独配置,因为因为日志的写性能影响zookeeper的性能 dataDir=E:\\zookeeper\\zookeeper-3.4.14\\data dataLogDir=E:\\zookeeper\\zookeeper-3.4.14\\log # the port at which the clients will connect # 客户端连接的端口 clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1
- 启动
启动的脚本在 /bin/目录下
linux启动 ./zkCli.sh -server localhost:2181
启动成功,进入客户端控制台
# 默认的节点叫zookeeper [zk: localhost:2181(CONNECTED) 1] ls / [zookeeper] # 创建一个节点 [zk: localhost:2181(CONNECTED) 11] create /changwu1 "num1" Created /changwu1 # 重新查看 [zk: localhost:2181(CONNECTED) 14] ls / [zookeeper, changwu1] # 获取节点的内容 [zk: localhost:2181(CONNECTED) 17] get /changwu1 num1 cZxid = 0x2 ctime = Mon Sep 16 15:56:27 CST 2019 mZxid = 0x2 mtime = Mon Sep 16 15:56:27 CST 2019 pZxid = 0x2 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 4 numChildren = 0 # 退出 quit # 删除一个节点 [zk: localhost:2181(CONNECTED) 32] delete /changwu1 [zk: localhost:2181(CONNECTED) 33] ls / [zookeeper] # 递归删除节点 rmr /path1/path2 这个path1 和 path2 其实是两个节点 # 修改节点数据 set /path "value" # 节点的状态 [zk: localhost:2181(CONNECTED) 50] stat /z1 cZxid = 0x5 ctime = Mon Sep 16 16:04:35 CST 2019 mZxid = 0x7 mtime = Mon Sep 16 16:06:31 CST 2019 pZxid = 0x6 cversion = 1 dataVersion = 1 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 8 numChildren = 1 # 创建永久有序节点 create -s /path
创建节点的形式,和我们mkdir,创建一个目录结构是相似的
集群搭建#
- 将zoo.cfg复制三份,并修改配置文件
第二个端口2887,用来同步Leader 和 Follower之间的数据, 第三个端口选举新的Leader使用
- 在tmp目录创建六个目录 分别是 zoo_data_1-3 zoo_logs_1-3
- 创建myid文件
[root@139 tmp]# echo 1 > zoo_data_1/myid [root@139 tmp]# echo 2 > zoo_data_2/myid [root@139 tmp]# echo 3 > zoo_data_3/myid
启动集群服务端
[root@139 bin]# ./zkServer.sh start ../conf/zoo1.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo1.cfg Starting zookeeper ... STARTED [root@139 bin]# ./zkServer.sh start ../conf/zoo2.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo2.cfg Starting zookeeper ... STARTED [root@139 bin]# ./zkServer.sh start ../conf/zoo3.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo3.cfg Starting zookeeper ... STARTED
分别查看各个节点的状态
[root@139 bin]# ./zkServer.sh status ../conf/zoo3.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo3.cfg Mode: follower [root@139 bin]# ./zkServer.sh status ../conf/zoo1.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo1.cfg Mode: leader [root@139 bin]# ./zkServer.sh status ../conf/zoo2.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo2.cfg Mode: follower
连接客户端
./zkCli -server localhost:服务端的端口号 zkCli.sh -server localhost:2181 zkCli.sh -server localhost:2182 zkCli.sh -server localhost:2183
添加观察者
- 和前三个一样,在tmp目录创建哨兵使用的目录 分别是 zoo_data_4 zoo_logs_4
- 在zoo_data_4目录下创建它myid文件,写入4
- 更改前三个节点的配置文件
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/tmp/zoo_data_1 dataLogDir=/tmp/zoo_logs_1 clientPort=2181 # 第一个端用于Leader和Leanner之间同步, 第二个端口,用户选举过程中的投票通信 server.1=localhost:2887:3887 server.2=localhost:2888:3888 server.3=localhost:2889:3889 server.4=localhost:2890:3890:observer
- 添加观察者的配置文件
tickTime=2000 initLimit=10 syncLimit=5 dataDir=/tmp/zoo_data_4 dataLogDir=/tmp/zoo_logs_4 # 观察者的配置 peerType=observer clientPort=2184 # 第一个端用于Leader和Leanner之间同步, 第二个端口,用户选举过程中的投票通信 server.1=localhost:2887:3887 server.2=localhost:2888:3888 server.3=localhost:2889:3889 server.4=localhost:2890:3890:observer
集群中的角色#
Leader#
发起投票和决议,以及更新最终状态
Follower#
接收处理客户端的请求,参与Leader发起的决议
Observer#
接受客户端的连接,将请求转发给Leader节点,但是它不参加投票,而仅仅同步Leader的状态,它是zookeeper拓展的方式
为什么会添加Observer呢? 这和zookeeper的工作方式息息相关:
一个zookeeper集群由多个Server组成,每一个Server都可以去处理多个client的请求, 如果是读请求,用当前的Server的本地数据库分本直接相应,但是,如果请求是改变zookeeper状态的写请求,就变得麻烦起来, zookeeper的leader节点会发起投票这个机制就是zab协议,超过半数的节点同意时,才会把这个操作加载到内存中,并对client进行回复
在这个过程中,zookeeper担任两个职能,一方面接受客户端的连接,另一方面又得去发起投票决议, 这两个功能限制了zookeeper的扩展想支持更多的客户端连接,就得添加server,但是server越来越多每次发起投票就变的沉重,于是Observer应运而生
Observer,不会参加投票,在其他节点处于投票阶段时,Observer接收client的连接,把连接转发的leader,而且,它还会收到投票的处理结果,保证自己和其他机器是数据一致性,从而大大提高系统的吞吐量
Learner#
和Leader一起同步状态的节点的统称,Observer和Follower统称为Learner
Zookeeper的CPA#
CP: 当集群中的节点仅仅剩下Leader Follower时, Leader挂了,就得重新选举,选举的过程中系统不可用
AP: Leader Follower Observer ,这三者组成的就群,实现了AP, 当Leader挂了,同样进行选举, 但是Observer可以继续接受client的请求,只不过Observer中的数据可能不是最新的数据