本文主要记录ZK中的相关特性,包括监听机制、权限控制等。
1. ZK特性 1.1 节点状态信息stat节点除了存储数据内容以外,还存储了数据节点本身的一些状态信息,通过stat命令可以获得状态信息的详细内容,如下所示。
zookeeper为数据节点引入了版本的概念,每个数据节点都有三类版本信息,对数据节点任何更新 *** 作都会引起版本号的变化。
版本号有点和我们经常使用的乐观锁类似。这里有两个概念说一下,一个是乐观锁,一个是悲观锁。
悲观锁:是数据库中一种非常典型且非常严格的并发控制策略。假如一个事务A正在对数据进行处理,那么在整个处理过程中,都会将数据处于锁定状态,在这期间其他事务无法对数据进行更新 *** 作。
乐观锁:乐观锁和悲观锁正好想法,它假定多个事务在处理过程中不会彼此影响,因此在事务处理过程中不需要进行加锁处理,如果多个事务对同一数据做更改,那么在更新请求提交之前,每个事务都会首先检查当前事务读取数据后,是否有其他事务对数据进行了修改。如果有修改,则回滚事务再回到zookeeper,version属性就是用来实现乐观锁机制的“写入校验“。
1.3 watcher机制zookeeper提供了分布式数据的发布/订阅功能,zookeeper允许客户端向服务端注册一个watcher监听,当服务端的一些指定事件触发了watcher,那么服务端就会向客户端发送一个事件通知。
zookeeper提供以下几种命令来对指定节点设置监听。
get [-s] [-w] path:监听指定path节点的修改和删除事件。同样该事件也是一次性触发。
get -w /node # 在其他窗口执行下面命令,会触发相关事件 set /node 123 delete /node
ls [-s] [-w] [-R] path : 监控指定path的子节点的添加和删除事件。
ls -w /node # 在其他窗口执行下面命令,会触发相关事件 create /node/node1 delete /node/node1
注意: 当前命令设置的监听是一次性的,就是说一旦触发了一次事件监听,后续的事件都不会响应。当然我们可以通过重复订阅来解决
stat [-w] path:作用和get完全相同。
addWatch [-m mode] path
addWatch的作用是针对指定节点添加事件监听,支持两种模式
PERSISTENT,持久化订阅,针对当前节点的修改和删除事件,以及当前节点的子节点的删除和新增事件。
PERSISTENT_RECURSIVE,持久化递归订阅,在PERSISTENT的基础上,增加了子节点修改的事件触发,以及子节点的子节点的数据变化都会触发相关事件(满足递归订阅特性)
1.4 Session会话机制如图所示,表示Zookeeper的session会话状态机制。
首先,客户端向Zookeeper Server发起连接请求,此时状态为CONNECTING
当连接建立好之后,Session状态转化为CONNECTED,此时可以进行数据的IO *** 作。
如果Client和Server的连接出现丢失,则Client又会变成CONNECTING状态
如果会话过期或者主动关闭连接时,此时连接状态为CLOSE
如果是身份验证失败,直接结束
2. ZK权限控制Zookeeper作为一个分布式协调框架,内部存储了一些分布式系统运行时的状态的数据,比如master选举、比如分布式锁。对这些数据的 *** 作会直接影响到分布式系统的运行状态。因此,为了保证zookeeper中的数据的安全性,避免误 *** 作带来的影响。Zookeeper提供了一套ACL权限控制机制来保证数据的安全。
ACL权限控制,使用: scheme : id : perm 来标识。
Scheme(权限模式),标识授权策略
ID(授权对象)
Permission:授予的权限
ZooKeeper的权限控制是基于每个znode节点的,需要对每个节点设置权限,每个znode支持设置多种权限控制方案和多个权限,子节点不会继承父节点的权限,客户端无权访问某节点,但可能可以访问它的子节点。
2.1 Scheme权限模式Zookeeper提供以下权限模式,所谓权限模式,就是使用什么样的方式来进行授权。
world:默认方式,相当于全部都能访问。
auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)
digest:即用户名:密码这种方式认证,这也是业务系统中最常用的。用 username:password 字符串来产生一个MD5串,然后该串被用来作为ACL ID。认证是通过明文发送username:password 来进行的,当用在ACL时,表达式为username:base64 ,base64是password的SHA1摘要的编码。
ip:通过ip地址来做权限控制,比如 ip:192.168.1.1 表示权限控制都是针对这个ip地址的。也可以针对网段 ip:192.168.1.1/24,此时addr中的有效位与客户端addr中的有效位进行比对。
2.2 ID授权对象指权限赋予的用户或一个指定的实体,不同的权限模式下,授权对象不同:
Id ipId1 = new Id("ip", "192.168.190.1"); Id ANYONE_ID_UNSAFE = new Id("world", "anyone");2.3 Permission权限类型
指通过权限检查后可以被允许的 *** 作,create /delete /read/write/admin
Create 允许对子节点Create *** 作
Read 允许对本节点GetChildren 和GetData *** 作
Write 允许对本节点SetData *** 作
Delete 允许对子节点Delete *** 作
Admin 允许对本节点setAcl *** 作
权限模式(Schema)和授权对象主要用来确认权限验证过程中使用的验证策略: 比如ip地址、digest:username:password,匹配到验证策略并验证成功后,再根据权限 *** 作类型来决定当前客户端的访问权限。
2.4 在控制台上实现权限 *** 作在Zookeeper中提供了ACL相关的命令如下。
getAcl getAcl2.4.1 World方式读取ACL权限 setAcl setAcl 设置ACL权限 addauth addauth 添加认证用户
我们创建一个节点后默认就是world模式。
其中, cdrwa,分别对应 create . delete. read .write . admin.
[zk: localhost:2181(CONNECTED) 14] create /world Created /world [zk: localhost:2181(CONNECTED) 15] getAcl /world 'world,'anyone : cdrwa [zk: localhost:2181(CONNECTED) 16] setAcl /world:anyone:acd setAcl [-s] [-v version] [-R] path acl [zk: localhost:2181(CONNECTED) 17] setAcl /world world:anyone:acd [zk: localhost:2181(CONNECTED) 18] getAcl /world 'world,'anyone : cda2.4.2 IP模式
在ip模式中,首先连接到zkServer的命令需要使用如下方式:
./zkCli.sh -server 192.168.221.120:2181
接着按照IP的方式 *** 作如下:
[zk: 192.168.221.120:2181(CONNECTED) 0] create /ip-model Created /ip-model [zk: 192.168.221.120:2181(CONNECTED) 2] setAcl /ip-model ip:127.0.0.1:cdrwa,ip:192.168.221.120:cdrwa [zk: 192.168.221.120:2181(CONNECTED) 3] getAcl /ip-model 'ip,'127.0.0.1 : cdrwa 'ip,'192.168.221.120 : cdrwa2.4.3 Auth模式
auth模式的 *** 作如下:
[zk: localhost:2181(CONNECTED) 5] create /auth Created /auth [zk: localhost:2181(CONNECTED) 6] addauth digest cc:cc # 增加授权用户,明文用户名和密码,zk会对密码加密 [zk: localhost:2181(CONNECTED) 7] setAcl /auth auth:mic:cdrwa # 授予权限 [zk: localhost:2181(CONNECTED) 8] getAcl /auth 'digest,'cc:8/1tijQ2Mu1QuGMyP+DoAciB06I= : cdrwa
当我们退出当前的会话后,再次连接,执行如下 *** 作,会提示没有权限.
[zk: localhost:2181(CONNECTED) 0] get /auth Insufficient permission : /auth
这时候,我们需要重新授权:
[zk: localhost:2181(CONNECTED) 1] addauth digest cc:cc [zk: localhost:2181(CONNECTED) 2] get /auth null2.4.4 Digest
使用语法,会发现使用方式和Auth模式相同。
setAcl /digest digest:用户名:密码:权限
但是有一个不一样的点,密码需要用加密后的,否则无法被识别。
密码: 用户名和密码加密后的字符串。
使用下面程序生成密码:
public static void main(String[] args) throws Exception { String up = "cc:cc"; byte[] digest = MessageDigest.getInstance("SHA1").digest(up.getBytes()); String encodeString = base64.getEncoder().encodeToString(digest); System.out.println(encodeString); }
得到:8/1tijQ2Mu1QuGMyP+DoAciB06I=
再回到client上进行如下 *** 作:
[zk: localhost:2181(CONNECTED) 3] create /digest Created /digest [zk: localhost:2181(CONNECTED) 4] setAcl /digest digest:cc:8/1tijQ2Mu1QuGMyP+DoAciB06I=:cdrwa [zk: localhost:2181(CONNECTED) 5] getAcl /digest 'digest,'cc:8/1tijQ2Mu1QuGMyP+DoAciB06I= : cdrwa
当退出当前会话后,需要再次授权才能访问**/digest**节点:
[zk: localhost:2181(CONNECTED) 0] get /digest Insufficient permission : /digest [zk: localhost:2181(CONNECTED) 1] addauth digest cc:cc [zk: localhost:2181(CONNECTED) 2] get /digest null
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)