一、关于zookeeper

Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储, Zookeeper 作用主要是用来维护和监控存储的数据的状态变化,通过监控这些数据状态的变化,从而达到基于数据的集群管理。

简单的说,zookeeper=文件系统+通知机制。

1. ZNode节点

ZNode被分为持久(persistent)节点,顺序(sequential)节点和临时(ephemeral)节点。

  • 持久节点:即使在创建该特定znode的客户端断开连接后,持久节点仍然存在。默认情况下,除非另有说明,否则所有znode都是持久的。
  • 顺序节点:顺序节点可以是持久的或临时的。当一个新的znode被创建为一个顺序节点时,ZooKeeper通过将10位的序列号附加到原始名称来设置znode的路径。例如,如果将具有路径 /test 的znode创建为顺序节点,则ZooKeeper会将路径更改为 /test0000000001 ,并将下一个序列号设置为0000000002。如果两个顺序节点是同时创建的,那么ZooKeeper不会对每个znode使用相同的数字。顺序节点在锁定和同步中起重要作用。
  • 临时节点:客户端活跃时,临时节点就是有效的。当客户端与ZooKeeper集合断开连接时,临时节点会自动删除。因此,只有临时节点不允许有子节点。如果临时节点被删除,则下一个合适的节点将填充其位置。临时节点在leader选举中起着重要作用。

2. Session回话

会话对于ZooKeeper的操作非常重要。会话中的请求按FIFO顺序执行。一旦客户端连接到服务器,将建立会话并向客户端分配会话ID 

客户端以特定的时间间隔发送心跳以保持会话有效。如果ZooKeeper集合在超过服务器开启时指定的期间(会话超时)都没有从客户端接收到心跳,则它会判定客户端死机。

会话超时通常以毫秒为单位。当会话由于任何原因结束时,在该会话期间创建的临时节点也会被删除。

3.Watcher监视

监视是一种简单的机制,使客户端收到关于ZooKeeper集合中的更改的通知。客户端可以在读取特定znode时设置Watches。Watches会向注册的客户端发送任何znode(客户端注册表)更改的通知。

Znode更改是与znode相关的数据的修改或znode的子项中的更改。只触发一次watches。如果客户端想要再次通知,则必须通过另一个读取操作来完成。当连接会话过期时,客户端将与服务器断开连接,相关的watches也将被删除。

二、Zookeeper客户端命令

执行bin/zkCli.sh连接zookeeper服务器后,我们随便敲一个aa然后回车,可以看到支持如下命令:

stat path [watch] --- 查看节点状态
set path data [version] --- 设置节点数据
ls path [watch] --- 列出子节点
delquota [-n|-b] path --- 删除节点配额
ls2 path [watch] --- 列出子节点,并显示当前节点信息
setAcl path acl --- 设置节点权限
setquota -n|-b val path --- 设置节点配额
history --- 列出历史命令
redo cmdno --- 执行历史命令
printwatches on|off
delete path [version] --- 删除节点,如果待删除节点包含子节点则删除失败
sync path
listquota path --- 列出节点配额
get path [watch] --- 获取节点数据
create [-s] [-e] path data acl --- 创建子节点
addauth scheme auth --- 增加zookeeper用户认证
quit --- 退出zkCli
getAcl path --- 查询节点权限
close --- 关闭当前连接
connect host:port --- 连接zkServer

1.  ls

此命令用于列出和显示znode的子项。ls命令要求路径以/开头,并支持tab键自动补全。例如:

  • 执行:ls /                        输出[dubbo, task, zookeeper, test, disconf]: 说明根节点下包含5个子节点。
  • 执行:ls /test                 输出[test1-2, test1-1]:说明/test节点下面有2个节点。
  • 执行:ls /test/test1-2     输出[]:说明/test/test1-2节点下面没有子节点。

2.  ls2

此命令也用于列出和显示znode的子项,与ls命令不同的是,该命令同时列出该节点的time、version等信息。例如:

执行 ls /test , 输出

[test1-, test1-]
cZxid = 0x69043
ctime = Mon Sep :: CST
mZxid = 0x69043
mtime = Mon Sep :: CST
pZxid = 0x69045
cversion =
dataVersion =
aclVersion =
ephemeralOwner = 0x0
dataLength =
numChildren =

3.  create

命令格式: create [-s] [-e] path data acl

  • -s:创建顺序节点。当一个新的znode被创建为一个顺序节点时,ZooKeeper通过将10位的序列号附加到原始名称来设置znode的路径。
  • -e:创建临时节点。客户端活跃时,临时节点就是有效的。当客户端与ZooKeeper集合断开连接时,临时节点会自动删除。
  • path:待创建的节点路径。以/开头。
  • data:带创建的节点存储的数据内容。
  • acl:权限控制。后面再说。

例如:

  • 创建永久节点:create /test/test1-3 "nodeData"
  • 创建临时节点:create -e /test/test1-4 "nodeData"
  • 创建循序节点:create -s /test/test1-5 "nodeData"

执行完以上命令以后,再执行 ls /test,可以看到输出结果:[test1-4, test1-2, test1-3, test1-1, test1-50000000004],可以看到创建的顺序节点test1-5被增加了序列号。我们执行quit退出zkCli,再重新执行bin/zkCli.sh重新连接,执行 ls /test,输出结果:[test1-2, test1-3, test1-1, test1-50000000004],可以看到创建的临时节点test1-4已经没有了。

4.  get

命令格式: get path [watch]。它返回znode的关联数据和指定znode的元数据。你将获得信息,例如上次修改数据的时间,修改的位置以及数据的相关信息。

  • path:节点路径。以/开头。
  • watch:监控。后面再说。

例如:执行 get /test/test1-3 输出

"nodeData"
cZxid = 0x69046
ctime = Mon Sep :: CST
mZxid = 0x69046
mtime = Mon Sep :: CST
pZxid = 0x69046
cversion =
dataVersion =
aclVersion =
ephemeralOwner = 0x0
dataLength =
numChildren =

5.  set

命令格式 set path data [version]。设置指定znode的数据。

  • path:节点路径。以/开头。
  • data:节点数据内容。
  • version: 当前数据版本号。如果该参数和当前数据版本号不一致则会抛异常。

例如:执行 set /test/test1-3 "dataNode-New",然后我们再执行 get /test/test1-3 查看数据,输出:

"dataNode-New"
cZxid = 0x69046
ctime = Mon Sep :: CST
mZxid = 0x6904b
mtime = Mon Sep :: CST
pZxid = 0x69046
cversion =
dataVersion =
aclVersion =
ephemeralOwner = 0x0
dataLength =
numChildren =

可以看到dataVersion已经发生了改变,当前 dataVersion = 1。

6.  delete

命令格式:delete path [version]。删除指定节点,如果要删除的节点包含子节点则会删除失败。

  • path:节点路径。以/开头。
  • version: 当前数据版本号。如果该参数和当前数据版本号不一致则会抛异常。

例如:执行 delete /test/test1-3,再执行 ls /test,输出:[test1-2, test1-1, test1-50000000004],可以看到test1-3这个节点已经被删除掉了。

7.  addauth

命令格式:addauth scheme auth。该命令为zookeeper增加一个用户认证,例如:addauth digest zookeeper:zookeeper-pass。其中zookeeper为用户名,zookeeper-pass为密码。

8.  history

命令格式:history。该命令用来查看历史命令,查询到的历史命令前会有编号,提供redo操作。

9.  redo

命令格式:redo cmdno。再次执行历史命令,配合history命令使用。参数cmdno即为history命令执行结果中的编号

三、Zookeeper权限控制

zookeeper支持的命令中,有如下两条命令是和权限相关的:

  • setAcl path acl
  • getAcl path
  • create [-s] [-e] path data acl

zookeeper共支持5中权限,分别是

  • create:创建节点
  • delete:删除节点
  • read:读取节点数据以及子节点
  • write:修改节点数据
  • admin:设置节点权限

zookeeper的ACL,可以从三个维度来理解:一是scheme;二是user;三是permission。通常表示为scheme:id:permissions。

授权模式

  • world: 表示所有,创建节点时默认此权限范围。有唯一的id是anyone。例如:setAcl /test/test1-1 world:anyone:cdrwa。表示/test/test1-1节点所有人都可以执行cdrwa操作。
  • auth:它不需要id,只要是通过认证的user都有权限。例如:setAcl /test/test1-2 auth:zookeeper:zookeeper-pass:cdrwa表示通过密码验证的用户名为zookeeper的用户可执行cdrwa操作。当然,执行此命令的前提是已经通过addauth命令添加了该用户名密码的用户。执行完setAcl命令后,再执行getAcl /test/test1-2,返回输出结果:
    'digest,'zookeeper:hdtnoeyerDQpPGLJ41lW1u1lCSA=
    : cdrwa

    请注意上面输出结果的hdtnoeyerDQpPGLJ41lW1u1lCSA=,该值紧接着我们就会用到。

  • digest:类似于auth授权。与auth授权的区别在于,输入命令的时候,用户密码需要先进行SHA-1加密再进行Base64编码。首先,先生成加密后的密码,执行:echo -n zookeeper:zookeeper-pass | openssl dgst -binary -sha1 | openssl base64,输出:hdtnoeyerDQpPGLJ41lW1u1lCSA=。可以看到该输出值即为auth授权后重新getAcl得到的值。然后,执行digest授权:setAcl /test/test1-3 digest:zookeeper:hdtnoeyerDQpPGLJ41lW1u1lCSA=:cdrwa。通过 getAcl /test/test1-3 可以看到授权结果和 getAcl /test/test1-2完全一致
  • ip:它对应的id为客户机的IP地址,设置的时候可以设置一个ip段,比如执行:setAcl /test/test1-4 ip:192.168.1.0/16:cdrwa, 表示匹配前16个bit的IP段。

四、quota配额

zookeeper可以在znode上设置配额限制。如果超出了配置限制,zookeeper将会在log日志中打印WARN日志。如果超出配额限制,并不会停止行为操作。

1.  setquota

命令格式:setquota -n|-b val path。为节点设定配额。例如命令:setquota -n 10 /test/test1-1

  • -n :限制子节点个数
  • -b :限制节点数据长度
  • val :  限制的具体的值
  • path : 要做限制的节点路径

2.  delquota

命令格式:delquota [-n|-b] path。删除节点配额。例如命令:delquota  -n /test/test1-1

  • -n|-b : 要删除的配额类型
  • path : 要做限制的节点路径

3.  listquota

命令格式:listquota path。列出节点设置的配额。例如命令:listquota  /test/test1-1

五、zookeeper in java

@Test
public void testClient() throws IOException, InterruptedException, KeeperException {
final String zookeeperHost = "10.5.31.155";
final String zookeeperPort = "2181";
// 链接zk服务器
final CountDownLatch countDownLatchConnect = new CountDownLatch(1);
final ZooKeeper zooKeeper = new ZooKeeper(zookeeperHost + ":" + zookeeperPort, 60000, event -> {
if (event.getState().equals(Watcher.Event.KeeperState.SyncConnected)) {
countDownLatchConnect.countDown();
}
});
countDownLatchConnect.await(); // watch节点 并执行创建
zooKeeper.exists("/clientTestNode", System.out::println);
zooKeeper.create("/clientTestNode", "clientTestNodeData".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); // watch节点 并执行删除
zooKeeper.exists("/clientTestNode", System.out::println);
zooKeeper.delete("/clientTestNode", -1); // 1. 创建节点 2. watch节点数据 3. 修改节点数据 4. 删除节点
zooKeeper.create("/clientTestNode", "clientTestNodeData".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
byte[] dataOld = zooKeeper.getData("/clientTestNode", System.out::println, null);
System.out.println(new String(dataOld));
zooKeeper.setData("/clientTestNode", "clientTestNodeDataNew".getBytes(), -1);
byte[] dataNew = zooKeeper.getData("/clientTestNode", System.out::println, null);
System.out.println(new String(dataNew));
zooKeeper.delete("/clientTestNode", -1); // 1. 创建节点 2. 监控节点的子节点 3. 创建子节点 4. 监控节点子节点 5. 删除子节点
zooKeeper.create("/clientTestNode", "clientTestNodeData".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
zooKeeper.getChildren("/clientTestNode", System.out::println, null);
zooKeeper.create("/clientTestNode/child1", "child1Data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
zooKeeper.getChildren("/clientTestNode", System.out::println, null);
zooKeeper.create("/clientTestNode/child2", "child2Data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
zooKeeper.getChildren("/clientTestNode", System.out::println, null);
zooKeeper.delete("/clientTestNode/child1", -1);
zooKeeper.getChildren("/clientTestNode", System.out::println, null);
zooKeeper.delete("/clientTestNode/child2", -1);
zooKeeper.delete("/clientTestNode", -1); }

需要注意的点:

  1. 由于zookeeper的连接是异步过程,所以执行new Zookeeper之后不要紧接着执行zookeeper命令。否则可能会出现丢失连接异常。
  2. 由于zookeeper的watcher是一次性有效(即zookeeper回调watcher后该watcher即被删除),所以会出现重复注册watcher的现象

zookeeper基础教程的更多相关文章

  1. Zookeeper基础教程(六):.net core使用Zookeeper

    Demo代码已提交到gitee,感兴趣的更有可以直接克隆使用,地址:https://gitee.com/shanfeng1000/dotnetcore-demo/tree/master/Zookeep ...

  2. Zookeeper基础教程(五):C#实现Zookeeper分布式锁

    分布式锁 互联网初期,我们系统一般都是单点部署,也就是在一台服务器完成系统的部署,后期随着用户量的增加,服务器的压力也越来越大,响应速度越来越慢,甚至出现服务器崩溃的情况. 为解决服务器压力太大,响应 ...

  3. Zookeeper基础教程(二):Zookeeper安装

    上一篇说了,一个Zookeeper集群一般认为至少需要3个节点,所以我们这里安装需要准备三台虚拟机: # 192.168.209.133 test1 # 192.168.209.134 test2 # ...

  4. Zookeeper基础教程(四):C#连接使用Zookeeper

    Zookeeper作为分布式的服务框架,虽然是java写的,但是强大的C#也可以连接使用. C#要连接使用Zookeeper,需要借助第三方插件,而现在主要有两个插件可供使用,分别是ZooKeeper ...

  5. Zookeeper基础教程(三):Zookeeper连接使用—zkCli

    上一篇介绍Zookeeper的安装,并介绍了使用ZooInspector连接Zookeeper,这里主要介绍以命令行的形式介绍Zookeeper 假如我们已经安装了Zookeeper集群,集群中的安装 ...

  6. Zookeeper基础教程(一):认识Zookeeper

    引用百度百科的话 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服 ...

  7. ActiveMQ基础教程(二):安装与配置(单机与集群)

    因为本文会用到集群介绍,因此准备了三台虚拟机(当然读者也可以使用一个虚拟机,然后使用不同的端口来模拟实现伪集群): 192.168.209.133 test1 192.168.209.134 test ...

  8. Kafka基础教程(二):Kafka安装

    因为kafka是基于Zookeeper的,而Zookeeper一般都是一个分布式的集群,尽管kafka有自带Zookeeper,但是一般不使用自带的,都是使用外部安装的,所以首先我们需要安装Zooke ...

  9. Spring Cloud Alibaba基础教程:Sentinel使用Apollo存储规则

    上一篇我们介绍了如何通过Nacos的配置功能来存储限流规则.Apollo是国内用户非常多的配置中心,所以,今天我们继续说说Spring Cloud Alibaba Sentinel中如何将流控规则存储 ...

随机推荐

  1. POJ 3348:Cows 凸包+多边形面积

    Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7739   Accepted: 3507 Description ...

  2. 【转置】使用mysql转置表格行和列

    1.原始表 2.查询结果表 3.查询语句 1 SELECT 2 year1, 3 SUM( CASE WHEN mon= 1 THEN account END ) AS m1, 4 SUM( CASE ...

  3. 【HITB GSEC CTF 2017】1000levels

    https://files.cnblogs.com/files/p4nda/498a3f10-8976-4733-8bdb-30d6f9d9fdad.gz #通过阅读天枢战队大佬们的wp调试的结果 首 ...

  4. shell-Startup-Files

    shell-Startup-Files 1. 相关阅读 2. 主流shell 3. shell实例类型 4. Shell启动文件的必要元素 4.1 路径: 命令路径, 4.2 提示符 5. 主流she ...

  5. Day4 - L - Tram POJ - 1847

    Tram network in Zagreb consists of a number of intersections and rails connecting some of them. In e ...

  6. 利用 vuex 实现一个公用搜索器

    安装 npm i vuex vuex 的使用 先创建好如图所示的文件: 编写 modules 下的 params.js const param = { state: { params: {} }, m ...

  7. 学会C#

    一.字符串插值 (String Interpolation) C# 6之前我们拼接字符串时需要这样 var Name = "Jack"; var results = "H ...

  8. 05 MySQL数据类型的选择与使用

    数据类型的选择     1.CHAR与VARCHAR           存储/检索的方式不同.         CHAR是固定长度,而VARCHAR是可变长度         非SQLMode下,超 ...

  9. tomcat启动报错The JRE could not be found.Edit the server and change the JRE location

    解决: 在Windows->Preferences->Server->Runtime Environments 选择Tomcat->Edit,在jre中选择相应的jdk版本,完 ...

  10. ES6 之 Proxy

    概述 Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改. Proxy 可以理解在目标对象架设一个“拦截”层外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行 ...