通过上一篇的学习,对zookeeper大致有了一些了解,但是想在实际开发与合适的业务场景中使用,还是需要依赖更多深入的学习,同时在项目中不断的实实践,发现问题并解决,才能对技术有更清晰与独特的见解。
本文从几个方面去学习如何使用zookeeper。
1、通过原生的api进行操作
2、通过zkClient进行操作
3、使用curator进行操作
4、各种应用场景的实现
当然以上内容主要来源于他人的成果,同时经过测试与理解,更加方面自己去理解其中的要义。
zookeeper API:
1、引入zookeeper依赖jar
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
</dependency>
2、建立连接
public class ZookeeperConnection implements Watcher {
private ZookeeperProperties properties;
public static ZooKeeper zooKeeper;
private CountDownLatch countDownLatch = new CountDownLatch(1);
public ZookeeperConnection(ZookeeperProperties properties){
this.properties = properties;
}
public void connect(){
try {
zooKeeper = new ZooKeeper(properties.getAddress(),properties.getTimeout(),this);
countDownLatch.await();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("zookeeper connected!");
}
public void process(WatchedEvent event) {
if(event.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
}
}
}
3、API
创建节点:
zk.create("/node", data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT)
获取子节点:
zk.getChildren("/node", true)
获取数据:
zk.getData("/node", true, null)
设置数据:
zk.setData("/node","data".getBytes(),-1)
判断是否存在:
zk.exists("/node",watch)
删除节点:
zk.delete("/node",-1)
关于zk的api其实不多,但是我们需要知道的是在什么情况如何搭配使用,上面主要是通过同步的方式操作,当然我们在创建节点、设置数据、删除节点时都可以通过回调函数实现异步操作。同时需要注意的是,watch是一次性的,如果调用,下次如果需要继续监听指定节点,需要再次注册。
下面会对acl、watch进行一些说明。
zkClient使用:
1、引入zkClient依赖jar
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.9</version>
</dependency>
2、建立连接
ZkClient zkClient = new ZkClient("10.8.109.60:2181", 10000, 10000, new SerializableSerializer())
3、API调用
创建节点:
zkClient.create("/user",user, CreateMode.PERSISTENT)
删除节点:
zkClient.delete("/node") //节点不存在返回false,节点存在子节点则异常
zkClient.deleteRecursive("/pnode") //无论有无节点或子节点都能删除
获取子节点:
zkClient.getChildren("/")
获取数据:
zkClient.readData("/user", stat) //将状态会写入stat
设置数据:
zkClient.writeDataReturnStat("/", data, -1)
节点是否存在:
zkClient.exists("/node")
监听:
IZkChildListener
zkClient.subscribeChildChanges("/node", new IZkChildListener(){...}) //监听node节点的创建/删除、创建/删除子节点
IZkDataListener
zkClient.subscribeDataChanges("/", new IZkDataListener(){...}) //监听指定节点的数据改变
curator使用:
1、引入依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.4.0</version>
</dependency>
2、创建连接
RetryPolicy retryPolicyOne = new ExponentialBackoffRetry(1000, 3) //重试间隔、重试次数
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 5000, 5000, retryPolicyOne)
client.start();
或者
CuratorFramework client = CuratorFrameworkFactory
.builder()
.connectString("localhost:2181")
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicyThree)
.build()
client.start()
3、API
创建节点:
client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/node", "".getBytes())
删除节点:
// 删除(无子节点的)节点
client.delete().forPath("/a_node");
// 删除指定版本的(无子节点的)节点
client.delete().withVersion(4).forPath("/a_node");
// 删除节点(如果有子节点,也一并删除)
client.delete().deletingChildrenIfNeeded().forPath("/a_node");
// 删除指定版本的节点(如果有子节点,也一并删除)
client.delete().deletingChildrenIfNeeded().withVersion(4).forPath("/a_node");
// 只要Session有效,那么就会对指定节点进行持续删除,知道删除成功; 这是一种保障机制
client.delete().guaranteed().deletingChildrenIfNeeded().withVersion(4).forPath("/a_node");
获取子节点:
client.getChildren().forPath("/")
获取数据:
client.getData().storingStatIn(stat).forPath("/")
设置数据:
client.getData().storingStatIn(statOne).forPath("/")
节点是否存在:
client.checkExists().forPath("/")
监听:
//节点监听
NodeCache cache = new NodeCache(client,"/node")
cache.getListenable().addListener(new NodeCacheListener() { //节点创建、节点内容改变
@Override
public void nodeChanged() throws Exception {
byte[] newData = cache.getCurrentData().getData();
}
});
//子节点监听
final PathChildrenCache cache = new PathChildrenCache(client,"/node", true);
cache.start();
// 当目标节点的子节点被创建、子节点被删除、子节点数据内容发生变化等时,会触发监听方法
cache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
byte[] data;
switch (event.getType()){
case CHILD_ADDED :
System.out.println("新增子节点!");
break;
case CHILD_REMOVED :
System.out.println("删除子节点!");
break;
case CHILD_UPDATED :
System.out.println("修改子节点数据内容!");
break;
default :;
}
}
});
和zkClienet相比,zkClient监听的主要分为节点与数据,而curator则是针对本节点、子节点。
ACL与Watch:
1、在新建节点时,我们可以对该节点设置对应的ACL,保证在对节点的后续操作时都必须满足ACL的设定,那么ACL具体如何理解与设置?
其实对节点的访问控制主要是什么对象对该节点有什么样的操作,那么什么对象我们用Id表示,节点则是当前创建的node,而操作则有rwacd(READ\WRITE\ADMIN\CREATE\DELETE)。
而ACL的表达式一般格式为:scheme:id:perm,在zk客户端中我们可以这样来对节点设置acl。eg: world:anyone:wr
scheme:
world:默认方式,相当于全世界都能访问,唯一id为anyone
auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户),没有id
digest:即用户名:密码这种方式认证,这也是业务系统中最常用的,,setAcl <path> digest:<user>:<password(密文)>:<acl>
第二密码是经过sha1及base64处理的密文
echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
host:根据地质认证
ip:使用Ip地址认证
id:
anyone
perm:
CREATE: create
READ: getData getChildren
WRITE: setData
DELETE: delete
ADMIN: setAcl
代码示例:
//world
List<ACL> acls = ZooDefs.Ids.OPEN_ACL_UNSAFE;
//auth
new ACL(ZooDefs.Perms.ALL,new Id("auth","username:password"));
//digest
ACL aclDigest = new ACL(ZooDefs.Perms.ALL, new Id("digest", DigestAuthenticationProvider.generateDigest("username:password")));
//host
new ACL(ZooDefs.Perms.ALL,new Id("host","scl.com"));
//ip
new ACL(ZooDefs.Perms.ALL,new Id("ip","192.168.1.1/25"));
CLI示例:
auth:
>addauth digest <username>:<password>
>setAcl /node auth:<username>:wradc
digest:
>echo -n <user>:<password> | openssl dgst -binary -sha1 | openssl base64
>setAcl <path> digest:<user>:<BASE64[SHA-1[password]]>:<acl>
host:
>setAcl <apth> host:<host>:<acl> //支持后缀 没试过
ip:
>setAcl <path> ip:<ip/bits>:<acl> //支持ip段,*匹配 不管怎么设置,不是Authentication is not valid就是alc is valid
watch主要是在创建节点、获取数据、判断节点是否存在是触发,针对不同的行为或者是事件被触发时所作出的响应,在zookeeper中有以下事件:
EventType.NodeCreated
EventType.NodeDeleted
EventType.NodeDataChanged
EventType.NodeChildrenChaged
这些主要是围绕节点与数据变化时对应的事件,但是要注意,NodeDeleted会影响getChildren设置的watcher,详情可以看这个网站。
-
zookeeper应用场景:
在curator-recipes中其实对以下场景基本都有实现,主要是需要了解其实现原理。
通过zookeeper实现各种场景的应用确实不易,还需深入理解zookeeper,虽然zk的实现非常复杂,但是暴露的api还是比较简单,而且上面说到的场景在其他的jar包中也有实现,以上可能有些地方因为理解或者测试原因可能存在一定的问题,还是需要在不断实践过程中深入理解与实践才是学习的根本。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有