大家好,我是砖家小胖,前两篇文章我们分别介绍了Zookeeper的安装篇和原理篇,今天我们来熟悉下Zookeeper的相关API代码开发。
1.Gradle相关引入和配置log4j.properties
plugins {id 'java'}group 'com.hownoon'version '1.0-SNAPSHOT'sourceCompatibility = 1.8repositories {mavenCentral()maven {url 'http://maven.aliyun.com/nexus/content/groups/public/'}}dependencies {testCompile group: 'junit', name: 'junit', version: '4.12'compile 'org.apache.hadoop:hadoop-client:3.1.2'compile 'org.apache.zookeeper:zookeeper:3.6.1'compile 'junit:junit:4.13'}tasks.withType(JavaCompile) {options.encoding = "UTF-8"}
#hadoop.root.logger=DEBUG, console#log4j.rootLogger = DEBUG, consolehadoop.root.logger=DEBUG,console### 设置###log4j.rootLogger = debug,stdout,D,E### 输出信息到控制抬 ###log4j.appender.stdout = org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target = System.outlog4j.appender.stdout.layout = org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n### 输出DEBUG 级别以上的日志到文件F://logs/debug.log ###log4j.appender.D = org.apache.log4j.FileAppenderlog4j.appender.D.File = F:/test/log4j/debug.loglog4j.appender.D.Append = truelog4j.appender.D.Threshold = DEBUGlog4j.appender.D.layout = org.apache.log4j.PatternLayoutlog4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n### 输出ERROR 级别以上的日志到文件F://logs/error.log ###log4j.appender.E = org.apache.log4j.FileAppenderlog4j.appender.E.File = F:/test/log4j/error.loglog4j.appender.E.Append = truelog4j.appender.E.Threshold = ERRORlog4j.appender.E.layout = org.apache.log4j.PatternLayoutlog4j.appender.E.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
2.初始化Zookeeper客户端

url:ZK节点地址端口/Host
sessionTimeout:超时时间
Watcher:添加的监听器,我们引入了接口Watcher,所以填写this
3.监听器回调方法 process

ZK客户端初始化后会立即回调一次Process方法

我们通过返回的WatchEvent.getState可以判断ZK客户端连接状态,比如Event.KeeperState.SyncConnected。
WatchEvent.getType可以判断ZK节点服务端的不同监听事件,这玩意和Java Swing的ActionListener和Android开发的OnClickListener差不太多。
Event.EventType.NodeDataChanged:节点数据变化
Event.EventType.NodeCreated:节点创建
Event.EventType.NodeChildrenChanged:路径子节点变化
Event.EventType.NodeDeleted:节点删除
Event.EventType.DataWatchRemoved:
Event.EventType.ChildWatchRemoved:
Event.EventType.PersistentWatchRemoved:
WatchEvent.getPath可以区分同一监听事件的不同节点,通过不同节点的区分来完成相对应的操作。
4.同步创建节点



path:节点路径
data:节点值
ACL:权限
CreateMode:节点类型
CreateMode.PERSISTENT:创建永久节点
CreateMode.EPHEMERAL:创建临时节点
CreateMode.PERSISTENT_SEQUENTIAL:创建永久序号节点
CreateMode.EPHEMERAL_SEQUENTIAL:创建临时序号节点
4.异步创建节点

异步操作没有返回值,比同步多了个回调接口,AsyncCallback.Create2Callback

rc:返回0则说明创建成功
path:节点路径
ctx:为传入标识符,用于区分不同的节点创建
name:节点名字
stat:节点状态数据封装,比如stat.getDataLength,可获得节点值的长度,其实就是上篇文章我们讲的这个玩意。

运行结果

5.同步获得节点值

path:节点路径
watch:是否监听该节点
stat:节点状态数据封装

6.异步获取节点值

异步操作没有返回值,比同步多了个回调接口AsyncCallback.DataCallback
data:节点值
其余同上

7.同步修改节点值

path:节点路径
data:修改后的新值
version: dataVersion,节点数据版本号。 传入的节点数据版本号必须与修改前节点数据版本号相同,才能进行写修改操作。
这里我们传入了0值,将hello值修改为了hi,可以看到数据版本号从0变成了1


我们再次执行,传入不同数据版本号时,则抛出异常

8.异步修改节点值

回调接口:AsyncCallback.StatCallback
其余参数同上

9.同步查看节点是否存在

path:节点路径
watch:是否监听
10.异步查看节点是否存在

参数同上
11.同步获取节点列表


12.异步获取节点列表

13.同步删除节点

14.异步删除节点

version:dataVersion

15.监听节点
我们上篇文章讲过,无论是在Shell端或代码增删改中赋予True值注册监听,只能监听一次,监听过后就失效,所以要在监听事件里再次重写注册监听,难道就不能让监听一直有效么?接下来的监听方法,可以永久有效,除非客户端主动移除监听器。
同步监听节点:

多次修改test节点的值

均可监听到

异步监听节点:

16.PERSISTENT和PERSISTENT_RECURSIVE
AddWatchMode.PERSISTENT:只监听test该级节点,并不会监听子节点事件。
AddWatchMode.PERSISTENT_RECURSIVE:递归监听该节点及子节点事件。
测试:

修改/test/haha 节点的值

监听事件毫无反应

那么我们将参数换成PERSISTENT_RECURSIVE

修改/test/haha 节点的值

监听事件生效

测试完毕~!
上篇文章,我们说到,ZK集群遭遇大规模极端并发时会取到旧数据。其实在代码中是有解决方案的,客户端需要访问任何ZK节点时都能获得最新数据,只需在读请求时调用SYNC方法,强制ZK集群全部节点同步完才可对外提供服务,这样就能保证每次读取到的数据为最新数据,但这样ZK集群也同样牺牲掉了一定的高可用性能。
额,Zookeeper篇大概就是这个样子了,如果以后有时间,咱们还可以继续深入研究。但是最近工作比较忙,我得先去写爬虫程序了,接下来我们会先梳理一下HBase的相关知识。
再见~~~




