1 Watch
https://zookeeper.apache.org/doc/current/zookeeperProgrammers.html#ch_zkWatches
图解:

支持watch的命令
watch的注册基本上都是读事件
1 2 3 4 5
| help config [-c] [-w] [-s] get [-s] [-w] path ls [-s] [-w] [-R] path stat [-w] path
|
1.1 watch体验
分类:
get stat 监听节点数据的变化
ls (-R) 针对(子)节点的变化
1.1.1 监听节点数据变化
1 2 3 4 5 6 7 8 9 10 11 12
| create /zk-watch 111 get -w /zk-watch
set /zk-watch 222
get -w /zk-watch
|
1.1.2 监听(子)节点的创建和删除
1 2 3 4 5 6 7 8 9 10
| create /zk-watch/sub1 get -w /zk-watch
set /zk-watch/sub1 111
ls -w /zk-watch create /zk-watch/sub2 111
create /zk-watch/sub3 111
|
1.1.3 永久监听
1 2 3 4 5 6 7 8 9 10 11 12
| create /zk-watch-update 666 addWatch /zk-watch-update set /zk-watch-update 999 set /zk-watch-update 888 create /zk-watch-update/sub1 create /zk-watch-update/sub2 delete /zk-watch-update/sub1 set /zk-watch-update/sub2 222 create /zk-watch-update/sub2/sub1 111 delete /zk-watch-update/sub2/sub1 delete /zk-watch-update/sub2 delete /zk-watch-update
|
2 Monitoring-监控
2.1 The Four Letter Words
https://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_4lw
ZooKeeper响应一小组命令。每个命令由四个字母组成。您可以通过客户端端口的 telnet 或 nc 向 ZooKeeper 发出命令。说白了就是由4个字母组成的命令,可以通过telnet或ncat使用客户端向zkServere发出命令。
- 修改zoo.cfg文件
1 2 3 4 5 6
| (1)打开zoo.cfg文件 (2)添加一行配置: 4lw.commands.whitelist=* echo "4lw.commands.whitelist=*" >> zoo.cfg (3)重启zk服务 zkServer.sh restart
|
- 体验一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| (1)安装ncat: yum install -y nc (2)查看节点是否正常 echo ruok | ncat localhost 2181 (3)查看节点相关配置 echo conf | ncat localhost 2181 (4)查看节点更详细的状态 echo stat | ncat localhost 2181 (5)查看节点更详细的状态 echo srvr | ncat localhost 2181 (6)查看临时节点 echo dump| ncat localhost 2181 (7)查看watch get -w /zk-watch echo wchc| ncat localhost 2181 (8)查看server的env echo envi| ncat localhost 2181
|
2.2 AdminServer
https://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_adminserver
3.5.0 中的新功能:管理服务器是一个嵌入式 Jetty 服务器,为四个字母的单词命令提供 HTTP 接口。默认情况下,服务器在端口 8080 上启动,并通过转到 URL “/command/[命令名称]”(例如 http://localhost:8080/commands/stat)发出命令。命令响应以 JSON 形式返回。与原始协议不同,命令不限于四个字母的名称,命令可以有多个名称;例如,“STMK”也可以称为“set_trace_mask”。要查看所有可用命令的列表,请将浏览器指向 URL /command(例如,http://localhost:8080/commands)
2.3 JMX(Java Management Extensions)
(1)zkServer.sh中配置JMX
1 2 3 4 5
| ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=192.168.0.8 -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain"
|
(2)重启zkServer
(3)查看8888端口监听
(4)打开本地jconsole,连接指定JMX的ip和port:192.168.0.8:8888

3 ACL-权限
https://zookeeper.apache.org/doc/current/zookeeperProgrammers.html#sc_ZooKeeperAccessControl
3.1 ACL的组成
scheme : id : permission
- scheme:表示策略
(1)world 该scheme只有一个id,为anyone,表示所有人,格式为 world:anyone:permission
(2)auth 该scheme表示需要认证登录,也就是对应注册的用户需拥有权限才可以访问,格式为 auth:user:password:permission
(3)digest 该scheme表示需要密码加密才能访问,格式为 digest:username:BASE64(password):permission
(4)ip 该scheme表示指定的ip才能访问,格式为 ip:localhost:permission
(5)super 该scheme表示超管,拥有所有权限
id:表示允许访问的用户
permission:表示访问的权限
(1)CREATE: you can create a child node
(2)READ: you can get data from a node and list its children.
(3)WRITE: you can set data for a node
(4)DELETE: you can delete a child node
(5)ADMIN: you can set permissions
3.2 ACL体验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| create /zk-acl 111 getAcl /zk-acl
create /zk-jack 666 setAcl /zk-jack auth:jack:123:cdrwa
addauth digest jack:123 setAcl /zk-jack auth:jack:123:cdrwa getAcl /zk-jack
ls /zk-jack get /zk-jack
addauth digest jack:123 get /zk-jack
|
4 序列化与反序列化
常见的序列化方式:json、protobuf、thrif、avro等。Zookeeper使用的序列化方式是jute,Java类需要实现Record接口,底层使用的是DataOutput和 DataInput。
(1)引入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.7.1</version> </dependency>
|
(2)定义Java类并测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @Data @AllArgsConstructor @NoArgsConstructor public class Person implements Record{ private String username; private Integer age; @Override public void serialize(OutputArchive archive, String tag) throws IOException{ archive.startRecord(this, tag); archive.writeString(username, "username"); archive.writeInt(age, "age"); archive.endRecord(this, tag); } @Override public void serialize(InputArchive archive, String tag) throws IOException{ archive.startRecord(tag); username = archive.readString("username"); age = archive.readInt("age"); archive.endRecord(tag); } public static void main(String[] args) throws Exception{ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); BinaryOutputArchive binaryOutputArchive = BinaryOutputArchive.getArchive(byteArrayOutputStream); new Person("Jack", 16).serialize(binaryOutputArchive, "person"); ByteBuffer byteBuffer = ByteBuffer.wrap(byteArrayOutputStream.toByteArray()); ByteBufferInputStream byteBufferInputStream = new ByteBufferInputStream(byteBuffer); BinaryInputArchive binaryInputArchive = BinaryInputArchive.getArchive(byteBufferInputStream); Person person = new Person(); person.deserialize(binaryInputArchive, "person"); System.out.println(person.toString()); byteArrayOutputStream.close(); byteBufferInputStream.close(); } }
|
5 快照数据与事务日志
快照数据:记录所有ZNode节点及数据某一时刻的快照,保存在zoo.cfg文件配置项的dataDir目录的 version-2中,格式为snapshot.zxid 事务日志:记录每一次事务操作的记录,保存在dataLogDir[dataDir]目录的version-2中,格式为 log.zxid
数据与日志里都是二进制数据,不能直接打开,需要使用以下工具:
1 2
| zkSnapShotToolkit.sh snapshot.zxid zkTxnLogToolkit.sh log.zxid
|
5.1 zkServer第一次启动
zkServer第一次启动时,因为此时zxid的值为0,会生成一个snapshot.0的数据快照文件,对应的源码是FileTnxSnapLog#save方法。
文件的大小不会进行预分配,而是取决于内存DataTree的大小。
1 2
| snapLog.serialize(dataTree, sessionsWithTimeouts, snapshotFile, syncSnap); new SnapshotInfo(Util.getZxidFromName(snapShot.getName(), SNAPSHOT_FILE_PREFIX),snapShot.lastModified() / 1000)
|
查看快照日志文件内容
1
| zkSnapShotToolkit.sh snapshot.0
|
5.2 第一次创建事务日志文件
使用客户端连接zk server时,也是事务事件,会生成了一个log.1的事务日志文件,对应的源码是 FileTxnLog#append方法。
文件的大小会进行预分配,也就是FilePadding#preAllocaSize = 65536 * 1024 Byte = 64M 也就是说每个事务日志文件的默认大小是64M,可以直接在windows中查看文件。如果事务日志文件的空间剩余不足4KB,则会再次预分配64M的磁盘空间。从这里可以看出,快照文件和日志文件最好不要放在一起,防止文件句柄数的频繁打开。
1
| zkTxnLogToolkit.sh log.1
|
5.3 新建数据快照文件和事务日志文件
每进行一次事务操作,事务日志中都会增加一条记录,当经过snapCount(默认100000)的过半随机次数(即在5万到10万之间)的事务写入之后,就会触发一次快照数据文件生成,同时也会新生成一个事务日志文件。
注意:每一次重新启动zk server,如果之前有zxid的变化,则也会创建一个新的快照数据文件,同时在后续的事务操作中,也会新建一个新的事务日志文件。
具体源码见SyncRequestProcessor#shouldSnapshot()方法
1 2 3 4 5 6
| private boolean shouldSnapshot() { int logCount = zks.getZKDatabase().getTxnCount(); long logSize = zks.getZKDatabase().getTxnSize(); return (logCount > (snapCount / 2 + randRoll)) || (snapSizeInBytes > 0 && logSize > (snapSizeInBytes / 2 + randSize)); }
|
5.4 数据快照文件和事务日志文件的清理
QuorumPeerConfig
1 2
| purgeInterval=0 #触发自动清理的时间间隔,单位是小时,默认值为0,表示不开启自动清理的功能 snapRetainCount=3 #自动清理保留3个事务日志和快照数据
|
5.5 总结
针对每一次事务操作,都会将其保存到事务日志文件中,同时会将数据的变化应用到内存DataTree中。当经过了一定次数的事务操作后,则会将内存DataTree中的全量数据保存到数据快照文件中。