zk
节点类型
- 持久节点
- 节点创建后,一直都存在,除非删除操作,否则一直存在
-
create /A 1
- 临时节点
- 节点的生命周期和客户端的会话session绑定,会话失效,节点就不会存在,连接断开connection也会导致节点不会存在,由于节点会话超时时间过期。
- 临时节点下面无法创建子节点
-
create -e /B 1
- 顺序+持久节点
- 顺序节点是在父节点下面去创建,父节点会维护顺序,创建节点过程中,zk会自动给节点后加一个数字,作为新的节点名,数字最大是int最大值
-
create -s /C/c_ 1
- 顺序+临时节点
- 顺序节点和临时节点的特性
-
create -s -e /D/d_ 1
节点最大能存的数据量1M
命令
# 创建节点
> create /zk 1
# 只能删除单个节点,存在子节点删除不了父节点
> delete /zk
# 递归删
> rmr /zk
# 查
> get /zk
# 改
> set /zk 2
# 节点路径
> ls /zk
# acl权限
setAcl /zk schema:id:permission
getAcl /zk
acl权限
# 权限模式:授权对象:权限
schema:id:permission
# 添加用户密码、登录用户
> addauth digest zhangsan:123456
# 设置该用户acl
> setAcl /zk auth:zhangsan:123456:cdrwa
# 设置所有人对/zk节点权限
> setAcl /zk world:anyone:dra
- schema
- world 所有人,对应id为“anyone”
- ip ip地址
- auth 使用添加认证的用户认证
- digest 使用“用户名:密码”方式认证
- id
- ip ip地址
- Digest "用户名:密码"
- World "anyone"
- Super "用户名:密码"
- permission
- c 创建子节点
- d 删除子节点
- r 读取节点信息以及显示子节点列表
- w 设置节点信息
- a admin,可以设置访问控制列表
节点信息
# 值
1
# 创建节点的事务id
cZxid = 0x100000002
# 创建节点的时间
ctime = Wed Mar 18 15:24:08 CST 2020
# 修改节点的事务id
mZxid = 0x100000002
# 修改节点的时间
mtime = Wed Mar 18 15:24:08 CST 2020
# 子节点的事务id,包含创建、修改、删除
pZxid = 0x100000006
# 对子节点进行更改的次数
cversion = 4
# 对节点进行更改的次数
dataVersion = 0
# 对节点acl权限更改的次数
aclVersion = 0
# 0x0表示持久节点,不是为临时节点,表示临时节点的session id
ephemeralOwner = 0x0
# 数据长度
dataLength = 1
# 子节点数量
numChildren = 4
watch
zk客户端
- Zookeeper
- watcher实现发布/订阅
- session过期删除临时节点和watcher,无法重连
- 没有领导者选举
- 只提供byte数组的接口
- 异常处理
- 一次性watcher
# new zookeeper()默认的watcher,默认的watch可以执行多次
ZooKeeper zooKeeper = new ZooKeeper("localhost:2181", 1000, event -> System.out.println("zk状态改变"+event));
# 创建节点,存在节点创建报错
zooKeeper.create("/B","b".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
Stat stat = new Stat();
# getData增加watcher,其中watcher是一次性,其中要区分获取的data和watcher是分开的
byte[] data = zooKeeper.getData("/B", event -> System.out.println("获取数据"+event), stat);
# 参数为true,watcher使用的是默认的watcher,为false不使用watcher
zooKeeper.getData("/B",true,stat);
# 获取数据
zooKeeper.getData("/B", true, (rc, path, ctx, data1, stat1) -> System.out.println("获取数据callback"+new String(data1)),null);
- ZkClient
# 超时时间、连接时间、序列化
ZkClient zk = new ZkClient("localhost:2181",1000,1000,new SerializableSerializer());
# 创建临时节点
zk.createEphemeral("/C","c");
# 读
Object o = zk.readData("/C");
# 多次watcher,打印的内容是set操作影响
zk.subscribeDataChanges("/C", new IZkDataListener() {
@Override
public void handleDataChange(String s, Object o) throws Exception {
System.out.println("数据被改变了"+s+"==="+o);
}
@Override
public void handleDataDeleted(String s) throws Exception {
}
});
#写
zk.writeData("/C","cc");
zk.writeData("/C","ccc");
- Curator
Guava is to Java that Curator to Zookeeper
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("localhost:2181",1000,1000,new RetryNTimes(3,1000));
# 获取的是framework,必须要start
curatorFramework.start();
# 创建
curatorFramework.create().withMode(CreateMode.EPHEMERAL).forPath("/D","d".getBytes());
# 监听,多次watcher
NodeCache nodeCache = new NodeCache(curatorFramework,"/D");
# 为true就是在启动的时候会去比较一次,就不会打印监听内容,默认false,不会比较,会打印
nodeCache.start(true);
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("node cache change");
}
});
# 支持原生的watcher,只能一次监听
curatorFramework.getData().usingWatcher((CuratorWatcher) watchedEvent -> System.out.println("调用了watcher")).forPath("/D");
System.in.read();
领导者选举工具
# 领导者选举leaderlatch
# 创建临时顺序节点,拿序号最小的节点
List<CuratorFramework> curatorFrameworks = Lists.newArrayList();
List<LeaderLatch> leaderLatches = Lists.newArrayList();
for(int i=0;i<10;i++){
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("localhost:2181",new RetryNTimes(3,1000));
curatorFrameworks.add(curatorFramework);
curatorFramework.start();
LeaderLatch leaderLatch = new LeaderLatch(curatorFramework,"/leaderlatch","#"+i);
leaderLatch.start();
leaderLatches.add(leaderLatch);
}
TimeUnit.SECONDS.sleep(3);
for(LeaderLatch leaderLatch:leaderLatches){
if(leaderLatch.hasLeadership()){
System.out.println("====="+leaderLatch.getLeader().getId());
}
}
List<LeaderLatch> collect = leaderLatches.stream().filter(leaderLatch -> leaderLatch.hasLeadership()).collect(Collectors.toList());
System.out.println("####"+collect.get(0).getId());
leaderLatches.forEach(LeaderLatch::close);
curatorFrameworks.forEach(CuratorFramework::close);
# 领导者选举leaderSelector
# 根据锁机制
List<CuratorFramework> curatorFrameworks = Lists.newArrayList();
List<LeaderSelector> leaderSelectors = Lists.newArrayList();
for(int i=0;i<10;i++){
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("localhost:2181",new RetryNTimes(3,1000));
curatorFramework.start();
curatorFrameworks.add(curatorFramework);
LeaderSelector leaderSelector = new LeaderSelector(curatorFramework, "/leaderselector", new LeaderSelectorListener() {
@Override
public void takeLeadership(CuratorFramework curatorFramework) throws Exception {
System.out.println("当前leader"+curatorFramework.getZookeeperClient().getZooKeeper().getSessionId());
TimeUnit.SECONDS.sleep(5);
}
@Override
public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {
}
});
leaderSelector.start();
leaderSelectors.add(leaderSelector);
}
System.in.read();
leaderSelectors.forEach(LeaderSelector::close);
curatorFrameworks.forEach(CuratorFramework::close);
附录
idea导入zk源码
1. git clone git@github.com:apache/zookeeper.git
2. git checkout branch-3.4.13
3. ant eclipse
* 出现异常java.net.UnknownHostException: downloads.sourceforge.net
解决方案:build.xml downloads.sourceforge.net替换成ufpr.dl.sourceforge.net
4. build success
5. bulid>*.jar 加入到lib下即可