一. zookeeper时什么
ZooKeeper本身就是一个分布式程序(只要半数以上节点存活,ZooKeeper 就能正常服务)
ZooKeeper将数据保存在内存中,这也就保证了 高吞吐量和低延迟. 但是容量有限
ZooKeeper是高性能的。在“读”多于“写”的应用程序中尤其地高性能,因为“写”会导致所有的服务器间同步状态(CP)。
ZooKeeper有临时节点的概念
ZooKeeper底层其实只提供了两个功能.
1.①管理(存储、读取)用户程序提交的数据.一个个类似目录的节点和节点数据
2.为用户程序提交数据节点监听服务。Watch
二. zookeeper核心1- 数据结构
2.1 类文件系统数据结构
Zookeeper在内存中维护一个类似文件系统的数据结构:
image.png
目录节点
这个类文件系统中,每个子目录都被称为目录节点。每个节点提供增删改查操作。目录节点有6种类型:
- 持久化节点 一旦创建,永久存在(除非被删除)
- 临时节点 会话结束后,session在适当时机删除。
- 持久化顺序节点 自带顺序的持久化节点
- 临时顺序节点 自带顺序的临时节点
- 容器节点 没有子节点时,未来被服务器删掉
- TTL节点 带过期时间的节点,到期后被服务器删除
2.2. 基础操作
2.2.1 节点创建
create [‐s] [‐e] [‐c] [‐t ttl] path [data] [acl]
- 默认持久化节点
> create /test‐node some‐data
- -s: 顺序节点
create -s /test‐node some‐data
- -e: 临时节点
create -e /test‐node some‐data
- -c: 容器节点
create ‐c /container
- -t: 可以给节点添加过期时间,默认禁用,需要通过系统参数启用
create ‐t expire_time /ttl-node/ some-data
-Dzookeeper.extendedTypesEnabled=true, znode.container.checkIntervalMs : (Java system property only) New in 3.5.1: The time interval in milliseconds for each check of candidate container and ttl nodes. Default is "60000".
- 创建临时顺序节点
> create ‐s ‐e /ephemeral‐node/prefix‐
//多次执行将序号递增,每个目录一个,执行三次
/ephemeral‐node/prefix‐0000000000
/ephemeral‐node/prefix‐0000000001
/ephemeral‐node/prefix‐0000000002
//再次 create ‐s ‐e /ephemeral‐node/prefix2‐
/ephemeral‐node/prefix2‐0000000003
2.2.2 查看
2.2.2.1查看节点数据
get /test‐node ----some-data
2.2.2.2 查看节点状态
stat /test‐node
- cZxid:创建znode的事务ID(Zxid的值)。
- mZxid:最后修改znode的事务ID。
- pZxid:最后添加或删除子节点的事务ID(子节点列表发生变化才会发生改变)。
- ctime:znode创建时间。
- mtime:znode最近修改时间。
- dataVersion:znode的当前数据版本。
- cversion:znode的子节点结果集版本(一个节点的子节点增加、删除都会影响这个版本)。
- aclVersion:表示对此znode的acl版本。
- ephemeralOwner:znode是临时znode时,表示znode所有者的 session ID。 如果 znode不是临时znode,则该字段设置为零。
- dataLength:znode数据字段的长度。
-
numChildren:znode的子znode的数量。
image.png
2.2.2.3查看节点数据加状态
get -s /node-test
2.2.2.4 查看一级子节点
ls /node-test/
2.2.2.5 查看所有子节点
ls -R /node-test/
2.2.3 修改
节点名称时不可以修改的。 修改只能修改节点数据,即some-data,修改成功后节点状态信息跟着变更。 其中dataVersion会变更,利用这一点可以实现类似数据的乐观锁
> set /test-node/ data2
//带版本号修改,假设前一版本号1
>set -v 1 /test-node/ data3
2.2.4 删除
delete [‐v version] path
deleteall path
三. zookeeper核心2 监听通知机制
zookeeper提供了监听机制,客户端可以注册监听关心的节点变化。
- 节点本身 监听该节点的删除和更新(节点本身或者节点数据)
get ‐w /path // 注册监听的同时获取数据
stat ‐w /path // 对节点进行监听,且获取元数据信息
- 节点目录 监听该节点 子目录 增删
ls ‐w /path
- 递归子目录节点 所有子节点的变化
ls ‐R ‐w /path : ‐R 区分大小写,一定用大写
注意:所有的通知都是一次性的,及无论是对节点还是对目录进行的监听,一旦触发,对应的监听即被移除。递归子节点,监听是对所有子节点的,所以,每个子节点下面的事件同样只会被触发一次。
事件类型
客户端注册监听后,一旦发生相应变更,zookeeper就会给客户端发送相应事件。 事件类型包括:
- None: 连接建立事件
- NodeCreated: 节点创建
- NodeDeleted: 节点删除
- NodeDataChanged:节点数据变化
- NodeChildrenChanged:子节点列表变化
- DataWatchRemoved:节点监听被移除
- ChildWatchRemoved:子节点监听被移除
四. ACL 权限控制( Access Control List )
Zookeeper ACL 权限设置分为 3 部分组成,分别是:
- 权限模式(Scheme)
- 授权对象(ID)
- 权限信息 (Permission)
最终组成一条例如“scheme:id:permission”格式的 ACL 请求信息
4.1 权限模式
用来设置 ZooKeeper 服务器进行权限验证的方式.大体分为两种类型
- 范围验证
ZooKeeper 可以针对一个 IP 或者一段 IP 地址授予某种权限
- 口令验证
在 ZooKeeper 中这种验证方式是 Digest 认证,而 Digest 这种认证方式首先在客户端传送“username:password”这种形 式的权限表示符后,ZooKeeper 服务端会对密码 部分使用 SHA-1 和 BASE64 算法进行加密, 以保证安全性. 其中Super权限模式, 可以认为是一种特殊的 Digest 认证。具有 Super 权限的客户端 可以对 ZooKeeper 上的任意数据节点进行任意操作。
4.2 授权对象
- 范围验证 :IP
- 口令验证 :用户名,特殊的World 模式,授权系统中所有的用户
4.3 权限信息
- 数据节点(c: create)创建权限
授予权限的对象可以在数据节点下创建子节点;
- 数据节点(w: wirte)更新权限
授予权限的对象可以更新该数据节点;
- 数据节点(r: read)读取权限
授予权限的对象可以读取该节点的内容以及子节点的列表信息;
- 数据节点(d: delete)删除权限
授予权限的对象可以删除该数据节点的子节点;
- 数据节点(a: admin)管理者权限
授予权限的对象可以对该数据节点体进行 ACL 权限设置。
4.4 命令
- getAcl:获取某个节点的acl权限信息
- setAcl:设置某个节点的acl权限信息
- addauth: 输入认证授权信息,相当于注册用户信息,注册时输入明文密码,zk将以密文的形式存储
可以通过系统参数zookeeper.skipACL=yes进行配置,默认是no,可以配置为true, 则配置过的 ACL将不再进行权限检测
4.5 ACL实战
4.5.1 生成授权ID
代码
String sId = DigestAuthenticationProvider.generateDigest("gj:test");
System.out.println(sId);// gj:X/NSthOB0fD/OT6iilJ55WJVado=
命令
echo ‐n : | openssl dgst ‐binary ‐sha1 | openssl base64
4.5.2 设置ACL
节点创建的同时设置ACL
create [-s] [-e] [-c] path [data] [acl]
create /zk‐node datatest digest:gj:X/NSthOB0fD/OT6iilJ55WJVado=:cdrwa
用setAcl 设置
setAcl /zk‐node digest:gj:X/NSthOB0fD/OT6iilJ55WJVado=:cdrwa
4.5.3 增加授权信息
设置ACL的节点,访问受限。访问前需要增加授权信息
addauth digest gj:test
4.5.4 auth 明文授权
使用之前需要先 addauth digest username:password 注册用户信息,后续可以直接用明文授权.
> addauth digest u100:p100
// 这是u100用户授权信息会被zk保存,可以认为当前的授权用户为u100
create /node‐1 node1data auth:u100:p100:cdwra
4.5.5 IP授权模式
setAcl /node‐ip ip:192.168.109.128:cdwra
create /node‐ip data ip:192.168.109.128:cdwra
Super 超级管理员模式
在Super模式下超级管理员用户可以对Zookeeper上的节点进行任 何的操作。 需要在启动了上通过JVM 系统参数开启:
‐Dzookeeper.DigestAuthenticationProvider.superDigest=super:
五. ZooKeeper 内存数据和持久化
Zookeeper数据的组织形式为一个类似文件系统的数据结构,而这些数据都是存储在内存中的, 所以我们可以认为,Zookeeper是一个基于内存的小型数据库
5.1 内存数据
public class DataTree {
private final ConcurrentHashMap nodes =
new ConcurrentHashMap();
private final WatchManager dataWatches = new WatchManager();
private final WatchManager childWatches = new WatchManager();
}
public class DataNode implements Record {
byte data[];
Long acl;
public StatPersisted stat;
private Set children = null;
5.2 事务日志
类似redis AOF 的功能,将原本的随机持久化,变更顺序读写持久化,提高性能。
数据格式
从左到右分别记录了操作时间,客户端会话ID,CXID,ZXID,操作类型,节点路径,节点数据(用 #+ascii 码表示),节点版本。
Zookeeper进行事务日志文件操作的时候会频繁进行磁盘IO操作,事务日志的不断追加写操作会 触发底层磁盘IO为文件开辟新的磁盘块,即磁盘Seek。因此,为了提升磁盘IO的效率, Zookeeper在创建事务日志文件的时候就进行文件空间的预分配- 即在创建文件的时候,就向操 作系统申请一块大一点的磁盘块。这个预分配的磁盘大小可以通过系统参数 zookeeper.preAllocSize 进行配置。
事务日志文件名为: log.<当时最大事务ID>,应为日志文件时顺序写入的,所以这个最大事务 ID也将是整个事务日志文件中,最小的事务ID,日志满了即进行下一次事务日志文件的创建
5.3 数据快照
功能对比redis的持久化方式-快照。
数据快照用于记录Zookeeper服务器上某一时刻的全量数据,并将其写入到指定的磁盘文件中。 可以通过配置snapCount配置每间隔事务请求个数,生成快照,数据存储在dataDir 指定的目录 中,可以通过如下方式进行查看快照数据:
java ‐classpath .:slf4j‐api‐1.7.25.jar:zookeeper‐3.5.8.jar:zookeeper‐jute‐ 3.5.8.jar
org.apache.zookeeper.server.SnapshotFormatter
/usr/local/zookeeper/apac he‐zookeeper‐3.5.8‐bin/data‐dir/version‐2/snapshot.0
为了避免集群中所有机器在同一时间进行快照,实际的快照生成时机为事务数达到 [snapCount/2 + 随机数(随机数范围为1 ~ snapCount/2 )] 个数时始快照
快照数据主要时为了快速恢复, 事务日志文件是每次事务请求都会进行追加的操作,而快照是达 到某种设定条件下的内存全量数据。所以通常快照数据是反应当时内存数据的状态。事务日志是 更全面的数据,所以恢复数据的时候,可以先恢复快照数据,再通过增量恢复事务日志中的数据 即可。