zooKeeper是一个经典的分布式数据一致性解决方案, 致力于为分布式应用提供一个高性能、 高可用, 且具有严格顺序访问控制能力的分布式协调存储服务。
zooKeeper将全量数据存储在内存中, 并直接服务于客户端的所有非事务请求, 尤其适用于以读为主的应用场景
zooKeeper一般以集群的方式对外提供服务, 一般3 ~ 5台机器就可以组成一个可用的Zookeeper集群了, 每台机器都会在内存中维护当前的服务器状态, 并且每台机器之间都相
互保持着通信。 只要集群中超过一半的机器都能够正常工作, 那么整个集群就能够正常对外服务
对于来自客户端的每个更新请求, ZooKeeper都会分配一个全局唯一的递增编号,这个编号反映了所有事务操作的先后顺序
Zookeeper 集群工作的核心事务请求(写操作) 的唯一调度和处理者,保证集群事务处理的顺序性;
集群内部各个服务器的调度者。
对于 create, setData, delete 等有写操作的请求,则需要统一转发给leader 处理, leader 需要决定编号、执行操作,这个过程称为一个事务
处理客户端非事务(读操作) 请求,转发事务请求给 Leader;
参与集群 Leader 选举投票
观察者角色,观察 Zookeeper 集群的最新状态变化并将这些状态同步过来,其对于非事务请求可以进行独立处理,对于事务请求,则会转发给 Leader服务器进行处理。
不会参与任何形式的投票只提供非事务服务,通常用于在不影响集群事务处理能力的前提下提升集群的非事务处理能力;
[zk: localhost:2181(CONNECTED) 7] get /ns-1/tenant
cZxid = 0x6a0000000a
ctime = Wed Mar 27 09:56:44 CST 2019
mZxid = 0x6a0000000a
mtime = Wed Mar 27 09:56:44 CST 2019
pZxid = 0x6a0000000e
cversion = 2
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2
cZxid: 数据节点创建时的事务 ID
ctime: 数据节点创建时的时间
mZxid: 数据节点最后一次更新时的事务 ID
mtime: 数据节点最后一次更新时的时间
pZxid: 数据节点的子节点最后一次被修改时的事务 ID
cversion: 子节点的更改次数
dataVersion: 节点数据的更改次数
aclVersion: 节点的 ACL 的更改次数
ephemeralOwner: 如果节点是临时节点, 则表示创建该节点的会话的
SessionID; 如果节点是持久节点, 则该属性值为 0
dataLength: 数据内容的长度
numChildren: 数据节点当前的子节点个数
zookeeper中的节点有两种, 分别为临时节点和永久节点。节点的类型在创建时即被确定, 并且不能改变。
create [-s] [-e] path data #其中-s 为有序节点, -e 临时节点
更新节点的命令是 set , 可以直接进行修改eg:set /hadoop “345”
基于版本号进行更改时, 乐观锁机制, 当你传入的数据版本号(dataVersion) 和当前节点的数据版本号不符合时,zookeeper 会拒绝本次修改:eg: set /hadoop “3456” 1
version No is not valid : /hadoop
delete path [version]
和更新节点数据一样, 也可以传入版本号, 当你传入的数据版本号 (dataVersion)和当前节点的数据版本号不符合时,zookeeper 不会执行删除操作。
要想删除某个节点及其所有后代节点, 可以使用递归删除, 命令为 rmr path
get path
可以使用 stat 命令查看节点状态, 它的返回值和 get 命令类似, 但不会返回节点数据
查看节点列表有 ls path 和 ls2 path 两个命令, 后者是前者的增强, 不仅可以查看指定路径下的所有节点, 还可以查看当前节点的信息
使用 get path [watch] 注册的监听器能够在节点内容发生改变的时候, 向客户端发出通知。 需要注意的是 zookeeper 的触发器是一次性的 (One-time trigger), 即触发一次后就会立即失效。
使用 stat path [watch] 注册的监听器能够在节点状态发生改变的时候, 向客
户端发出通知
使用 ls path [watch] 或 ls2 path [watch] 注册的监听器能够监听该节点下所有子节点的增加和删除操作
权限模式(scheme) : 授权的策略
授权对象(id) : 授权的对象
权限(permission) : 授予的权限
- zooKeeper的权限控制是基于每个znode节点的, 需要对每个节点设置权限
- 每个znode支持设置多种权限控制方案和多个权限
- 子节点不会继承父节点的权限, 客户端无权访问某节点, 但可能可以访问它的子节点
Watcher实现由三个部分组成:
客户端首先将Watcher注册到服务端,同时将Watcher对象保存到客户端的Watch管
理器中。当ZooKeeper服务端监听的数据状态发生变化时,服务端会主动通知客户端,接着客户端的Watch管理器会触发相关Watcher来回调相应处理逻辑,从而完成整体的数据发布/订阅流程
Watcher是一个接口,任何实现了Watcher接口的类就是一个新的Watcher。Watcher内部包含了两个枚举类:KeeperState、EventType
了解完zk的基本特性,据此分析一下具体的使用场景案例
eg: 数据库用户名和密码信息放在一个配置文件中,应用读取该配置文件,配置文件信息放入缓存。若数据库的用户名和密码改变时候,还需要重新加载缓存,比较麻烦,通过ZooKeeper可以轻松完成,当数据库发生变化时自动完成缓存同步。
设计思路:
在单库单表型系统中,通常可以使用数据库字段自带的auto_increment属性来自动为每条记录生成一个唯一的ID。但是分库分表后,就无法在依靠数据库的auto_increment属性来唯一标识一条记录了。可以用zookeeper在分布式环境下生成全局唯一ID。
设计思路:
注:生产环境,一般采用别的方式:例如雪花算法等
分布式锁有多种实现方式,比如通过数据库、redis都可实现。作为分布式协同
工具ZooKeeper,当然也有着标准的实现方式。下面介绍在zookeeper中如何实现排他锁。
设计思路:
- leader从客户端收到一个写请求
- leader生成一个新的事务并为这个事务生成一个唯一的ZXID
- leader将这个事务提议(propose)发送给所有的follows节点
- follower节点将收到的事务请求加入到历史队列(history queue)中,并发送ack leader
- 当leader收到大多数follower(半数以上节点)的ack消息,leader会发送commit请求
- 当follower收到commit请求时,从历史队列中将事务请求commit
服务器状态
在集群初始化阶段,当有一台服务器server1启动时,其单独无法进行和完成
leader选举,当第二台服务器server2启动时,此时两台机器可以相互通信,每台机器都试图找到leader,于是进入leader选举过程。选举过程如下:
- 每个server发出一个投票。由于是初始情况,server1和server2都会将自己作为
leader服务器来进行投票,每次投票会包含所推举的服务器的myid和zxid,使用(myid, zxid)来表示,此时server1的投票为(1, 0),server2的投票为(2, 0),然后各自将这个投票发给集群中其他机器。- 集群中的每台服务器接收来自集群中各个服务器的投票。
- 处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票进行pk,pk规则如下优先检查zxid。zxid比较大的服务器优先作为leader。如果zxid相同,那么就比较myid。myid较大的服务器作为leader服务器。对于Server1而言,它的投票是(1, 0),接收Server2的投票为(2, 0),首先会比较两者的zxid,均为0,再比较myid,此时server2的myid最大,于是更新自己的投票为(2, 0),然后重新投票,对于server2而言,其无须更新自己的投票,只是再次向集群中所有机器发出上一次投票信息即可。
- 统计投票。每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息,对于server1、server2而言,都统计出集群中已经有两台机器接受了(2, 0)的投票信息,此时便认为已经选出了leader
- 改变服务器状态。一旦确定了leader,每个服务器就会更新自己的状态,如果是follower,那么就变更为following,如果是leader,就变更为leading
- 变更状态。leader挂后,余下的服务器都会将自己的服务器状态变更为looking,然后开始进入leader选举过程。
- 每个server会发出一个投票。在运行期间,每个服务器上的zxid可能不同,此时假定server1的zxid为122,server3的zxid为122,在第一轮投票中,server1和server3都会投自己,产生投票(1, 122),(3, 122),然后各自将投票发送给集群中所有机器。
- 接收来自各个服务器的投票。与启动时过程相同
- 处理投票。与启动时过程相同,此时,server3将会成为leader。
- 统计投票。与启动时过程相同。
- 改变服务器的状态。与启动时过程相同。
observer角色特点:
- 为了使用observer角色,在任何想变成observer角色的配置文件中加入如下配
置:peerType=observer- 并在所有server的配置文件中,配置成observer模式的server的那行配置追
加:observer,例如:server.3=192.168.60.130:2289:3389:observer
1、zookeeper java API
https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper
2、开源客户端curator
https://curator.apache.org/dependency-info.html
打赏地址