初识 zookeeper Zookeeper 它作为Hadoop项目中的一个开源子项目,是一个经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务。 1、zookeeper数据模型 zookeeper 维护了一个类似文件系统的数据结构,每个子目录(/微信、/微信/公众号)都被称作为 znode 即节点。和文件系统一样,我们可以很轻松的对 znode 节点进行增加、删除等操作,而且还可以在一个znode下增加、删除子znode,区别在于文件系统的是,znode可以存储数据(严格说是必须存放数据,默认是个空字符)。 由于zookeeper是目录节点结构,在获取和创建节点时,必须要以“/” 开头,否则在获取节点时会报错 Path must start with / character。 [zk: localhost:2181(CONNECTED) 13] get testCommand failed: java.lang.IllegalArgumentException: Path must start with / character 根节点名必须为“/XXX”,创建子节点时必须要带上根节点目录“/XXX/CCC”、“/XXX/AAA”。 例如:想要获取下图 程序员内点事 节点必须拼接完整的路径 get /微信/公众号/程序员内点事 get /微信/公众号/程序员内点事 在这里插入图片描述 znode被用来存储 byte级 或 kb级 的数据,可存储的最大数据量是1MB(请注意:一个节点的数据量不仅包含它自身存储数据,它的所有子节点的名字也要折算成Byte数计入,因此znode的子节点数也不是无限的)虽然可以手动的修改节点存储量大小,但一般情况下并不推荐这样做。 2、znode节点属性 一个znode节点不仅可以存储数据,还有一些其他特别的属性。接下来我们创建一个/test节点分析一下它各个属性的含义。 [zk: localhost:2181(CONNECTED) 6] get /test456cZxid = 0x59ac //ctime = Mon Mar 30 15:20:08 CST 2020mZxid = 0x59admtime = Mon Mar 30 15:22:25 CST 2020pZxid = 0x59accversion = 0dataVersion = 2aclVersion = 0ephemeralOwner = 0x0dataLength = 3numChildren = 0 节点属性 注解 cZxid 该数据节点被创建时的事务Id mZxid 该数据节点被修改时最新的事物Id pZxid 当前节点的父级节点事务Id ctime 该数据节点创建时间 mtime 该数据节点最后修改时间 dataVersion 当前节点版本号(每修改一次值+1递增) cversion 子节点版本号(子节点修改次数,每修改一次值+1递增) aclVersion 当前节点acl版本号(节点被修改acl权限,每修改一次值+1递增) ephemeralOwner 临时节点标示,当前节点如果是临时节点,则存储的创建者的会话id(sessionId),如果不是,那么值=0 dataLength 当前节点所存储的数据长度 numChildren 当前节点下子节点的个数 我们看到一个znode节点的属性比较多,但比较主要的属性还是zxid、version、acl 这三个。 Zxid: znode节点状态改变会导致该节点收到一个zxid格式的时间戳,这个时间戳是全局有序的,znode节点的建立或者更新都会产生一个新的。如果zxid1的值 < zxid2的值,那么说明zxid2发生的改变在zxid1之后。每个znode节点都有3个zxid属性,cZxid(节点创建时间)、mZxid(该节点修改时间,与子节点无关)、pZxid(该节点或者该节点的子节点的最后一次创建或者修改时间,孙子节点无关)。 zxid属性主要应用于zookeeper的集群,这个后边介绍集群时详细说。 Version: znode属性中一共有三个版本号dataversion(数据版本号)、cversion(子节点版本号)、aclversion(节点所拥有的ACL权限版本号)。 znode中的数据可以有多个版本,如果某一个节点下存有多个数据版本,那么查询这个节点数据就需要带上版本号。每当我们对znode节点数据修改后,该节点的dataversion版本号会递增。当客户端请求该znode节点时,会同时返回节点数据和版本号。另外当dataversion为 -1的时候可以忽略版本进行操作。对一个节点设置权限时aclVersion版本号会递增,下边会详细说ACL权限控制。 验证一下,我们修改/test节点的数据看看dataVersion有什么变化,发现dataVersion属性变成了 3,版本号递增了。 [zk: localhost:2181(CONNECTED) 10] set /test 8888cZxid = 0x59acctime = Mon Mar 30 15:20:08 CST 2020mZxid = 0x59b6mtime = Mon Mar 30 16:58:08 CST 2020pZxid = 0x59accversion = 0dataVersion = 3aclVersion = 0ephemeralOwner = 0x0dataLength = 4numChildren = 0 3、znode的类型 zookeeper 有四种类型的znode,在用客户端 client 创建节点的时候需要指定类型。 zookeeper.create("/公众号/程序员内点事", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); PERSISTENT-持久化目录节点 :client创建节点后,与zookeeper断开连接该节点将被持久化,当client再次连接后节点依旧存在。 PERSISTENT_SEQUENTIAL-持久化顺序节点 :client创建节点后,与zookeeper断开连接该节点将被持久化,再次连接节点还存在,zookeeper会给该节点名称进行顺序编号,例如:/lock/0000000001、/lock/0000000002、/lock/0000000003。 EPHEMERAL-临时目录节点 :client与zookeeper断开连接后,该节点即会被删除 EPHEMERAL_SEQUENTIAL-临时顺序节点 :client与zookeeper断开连接后,该节点被删除,会给该节点名称进行顺序编号,例如:/lock/0000000001、/lock/0000000002、/lock/0000000003。 节点的ACL权限控制 ACL:即 Access Control List (节点的权限控制),通过ACL机制来解决znode节点的访问权限问题,要注意的是zookeeper对权限的控制是基于znode级别的,也就说节点之间的权限不具有继承性,即子节点不继承父节点的权限。 zookeeper中设置ACL权限的格式由 : : 三段组成。 schema :表示授权的方式 world:表示任何人都可以访问 auth:只有认证的用户可以访问 digest:使用username :password用户密码生成MD5哈希值作为认证ID host/ip:使用客户端主机IP地址来进行认证 id:权限的作用域,用来标识身份,依赖于schema选择哪种方式。 acl:给一个节点赋予哪些权限,节点的权限有create,、delete、write、read、admin 统称 cdwra。 1、world:表示任何人都可以访问 我们用 getAcl 命令来看一下,没有设置过权限的znode节点,默认情况下的权限情况。 [zk: localhost:2181(CONNECTED) 12] getAcl /test'world,'anyone: cdrwa 看到没有设置ACL属性的节点,默认schema 使用的是world,作用域是anyone,节点权限是cdwra,也就是说任何人都可以访问。 那我们如果要给一个schema 为非world的节点设置world权限咋搞? setAcl /test world:anyone:crdwa 2、auth:只有认证的用户可以访问 schema 用auth授权表示只有认证后的用户才可以访问,那么首先就需要添加认证用户,添加完以后需要对认证的用户设置ACL权限。 addauth digest test:password(明文) 需要注意的是设置认证用户时的密码是明文的。 [zk: localhost:2181(CONNECTED) 2] addauth digest user:user //用户名:密码[zk: localhost:2181(CONNECTED) 5] setAcl /test auth:user:crdwa[zk: localhost:2181(CONNECTED) 6] getAcl /test'digest,'user:ben+k/3JomjGj4mfd4fYsfM6p0A=: cdrwa 实际上我们这样设置以后,就是将这个节点开放给所有认证的用户,setAcl /test auth:user:crdwa 相当于setAcl /test auth::crdwa。 3、digest:用户名:密码的验证方式 用户名:密码方式授权是针对单个特定用户,这种方式是不需要先添加认证用户的。 如果在代码中使用zookeeper客户端设置ACL,那么密码是明文的,但若是zk.cli等客户端操作就需要将密码进行sha1及base64处理。 setAcl digest: : : setAcl /test digest:user:jalRr+knv/6L2uXdenC93dEDNuE=:crdwa 那么密码如何加密嘞?有以下几种方式: 通过shell命令加密 echo -n : <password> | openssl dgst -binary -sha1 | openssl base64 使用zookeeper自带的类库org.apache.zookeeper.server.auth.DigestAuthenticationProvider生成 java -cp /zookeeper-3.4.13/zookeeper-3.4.13.jar:/zookeeper-3.4.13/lib/slf4j-api-1.7.25.jar \ org.apache.zookeeper.server.auth.DigestAuthenticationProvider \ root:rootroot:root->root:qiTlqPLK7XM2ht3HMn02qRpkKIE= 4、host/ip:使用客户端主机IP地址来进行认证 这种方式就比较好理解了,通过对特定的IP地址,也可以是一个IP段进行授权。…