zookeeper概述
zookeeper从设计模式角度来说:是一个基于观察者模式的分布式服务管理框架,负责存储和管理分布式数据,然后接受观察者的注册,一旦数据发生了变化,zookeeper负责通知已经在zk上注册过的观察者做出响应.
zk特点
- 一个leader 多个follower组成集群
- 集群只有有半数以上节点存活,zk集群就能对外正常服务,一般安装奇数台服务
- 全局数据一致性: 每个server保存一份相同的数据分布,client无论连接到哪一个server,数据都是一致的
- 更新请求顺序执行,来自同一个client的更新请求按其发送顺序依次执行
- 数据更新原子性,一次数据更新要么成功,要么失败
- 实时性,在一定时间范围内,client能够读到最新的数据
zk的数据结构
zookeeper数据模型与unix文件系统类似,整体上看做一棵树,每个节点称为一个ZNode.每一个ZNode默认能够存储1MB的数据,每一个ZNode可以通过其路径唯一标识.
应用场景
- 统一命名服务
- 统一通知管理
- 统一集群管理
- 服务器节点动态上线下线
- 软负载均衡
zk集群安装
-
下载软件包https://archive.apache.org/dist/zookeeper/zookeeper-3.5.7/
-
解压缩 tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /usr/local/zk
-
修改配置文件
-
拷贝一份配置文件 cp zoo_sampe.cfg zoo.cfg
-
修改ZK数据存放目录 dataDir=/usr/local/zk/apache-zookeeper-3.5.7-bin/data
-
zoo.cfg中添加集群节点规划
#######################cluster########################## server.1=node1:2888:3888 server.2=node2:2888:3888 server.3=node3:2888:3888
-
完整配置文件
# The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/usr/local/zk/apache-zookeeper-3.5.7-bin/data # the port at which the clients will connect clientPort=2181 #######################cluster########################## server.1=node1:2888:3888 server.2=node2:2888:3888 server.3=node3:2888:3888
-
-
在zk的数据目录文件下 配置myid文件 每个机器必须唯一 标识zk集群的唯一id
echo 1 > /usr/local/zk/apache-zookeeper-3.5.7-bin/data/myid
-
启动集群和查看状态
# 启动集群 bash bin/zkServer.sh start # 查看集群状态 bash bin/zkServer.sh status
配置文件详解
参数 | 描述 |
---|---|
tickTime | 通信心跳时间,Zookeeper服务器与客户端心跳时间,单位毫秒默认值2000 |
initLimit | leader和follower的通信时限 默认值10 表示leader和follower的初始连接最多容忍10次心跳(tickTime的数量) 默认10*2 = 20sec之后 leader和follower会判定为不能连接状态 |
syncLimit | leader和follower的通信时限, leader和follower通信时间如果超过了syncLimit * tickTime ,leader认为follower死亡,从服务器列表中踢出 |
dataDir | zk中保存数据的目录 生产一定需要修改! |
clientPort | 客户端连接端口 默认2181 |
server.[id] | 集群的配置 格式为 server.[id] = ip:port1:port2 id:是配置myid,zk启动时读取此文件,拿到里面的数据与zoo.cfg里面配置信息从而判断是哪个server ip表示服务器地址 port1:表示follower和leader服务器交换信息的端口 port2是集群用来选举leader的端口 |
zk选举机制
- SID: 服务器id,用来唯一标识一台zk集群中的服务器,所有机器不能重复与myid一致
- ZXID: 事务id,ZXID是一个事务ID,用来标识一次服务器状态的变更.某一个时刻集群中的每台服务器ZXID值不一定完全一致,与zk与客户端的更新请求处理逻辑相关
- Epoch: 每个leader的任期带好,没有leader时同一轮投票中的逻辑时钟值相同,每投完一轮增加
首次选举
- server1启动,发起一次选举,投S1自己一票,不够半数(3票),选举无法进行,S1保存LOOKING状态
- server2启动,发起一次选举,此时S1 S2先分别投自己一票,此时S1发现S2的myid比自己投票推举的(S1自身)要大,更改选票推举S2,此时S1服务器0票,S2服务器2票,但是还是没有达到半数,S1S2保持LOOKING状态
- server3启动,发起一次选举,此时S1,S2变更选票投S3,此时S3的票数超过变数,S3当选leader,S1,S2服务器变更状态为follower,此时集群可以对外提供服务
- server4启动,发起选举,此时S1 S2 S3已经不是LOOKING状态,不会变更选票信息,交换选票信息之后此时S3为3票,S4投自己1票,此时S4服从多数变更选票为S3,S4状态变更为follower
- server5 与 server4同理
leader宕机重新选举
- epoch大的直接胜出
- epoch相同,事务Id大的胜出
- 事务Id相同 集群Id大的胜出
例如 zk集群由5台服务器组成,SID分别为1 2 3 4 5,ZXID分别为 8 8 8 7 7,加入此时S3服务器是leader,某时候S3 和 S5宕机,此时开始选举新leader
1 2 4的 投票情况如下
机器名 | 选票情况(EPOCH,ZXID,SID) |
---|---|
S1 | (1,8,1) |
S2 | (1,8,2) |
S4 | (1,7,4) |
集群的EPOCH相同,进而比较ZXID事务id,此时S4的事务ID小于S1 S2, 进而比较 S1 和 S2 , S2的SID大于S1,此时S2当选
节点类型
zk中的节点可以按持久化类型分为持久节点和临时节点,也可以按节点是否有序分为 有序号节点和无序号节点
-
持久节点Persistent: 客户端与服务器断开链接之后,创建节点不删除
-
临时节点Ephemeral: 客户端与服务器断开链接之后,创建节点自己删除
-
有序号 创建znode时设置顺序标识,znode名称后面会附加一个值,序号是一个单挑递增的计数器,由父节点维护.在分布式系统中顺序号可以用于为所有事件进行全局排序,客户端可以通过顺序号推断事件的先后顺序 create -s /testWithNo “testWithNoNode” 如果原来没有序号节点,序号从 0 开始依次递增。如果原节点下已有 2 个节点,则再排 序时从 2 开始,以此类推
-
无序号 create /test “testNode” 创建普通节点