1.3 Zookeeper的架构

Zookeeper本身就时一个文件存储系统:Zookeeper内部存储着大量的znode,每一个znode节点都可以有多个子节点,每一个znode都可以单独的存储数据。

  • 持久的znode:永久的保存在Zookeeper
  • 持久有序的znode:永久的保存在Zookeeper。添加节点时,自动在节点名称后追加一个有序的序号。
  • 临时的znode:客户端和Zookeeper服务断开连接后,当前znode自动删除。
  • 临时有序的znode:客户端和Zookeeper服务断开连接后,当前znode自动删除。添加节点时,自动在节点名称后追加一个有序的序号。

Zookeeper提供的监听通知机制:客户端可以监听Zookeeper服务中的znode,在znode改变时,Zookeeper会通知所有监听的客户端。

1.4 Zookeeper常用命令

查询:

  • ls znode:查看当前节点的子节点
  • get znode:查看当前节点的数据和信息
  • 创建:
  • create [-s] [-e] znode znode数据:创建节点,-s代表有序节点,-e代表临时节点。
  • 修改:
  • set znode znode数据:修改znode的数据,zxid数据越新,zxid越大。
  • 删除:
  • delete znode:删除空节点
  • rmr znode:删节点,跑路。(rmr看版本,有的版本是deleteall)
1.5 Zookeeper集群的架构&投票机制

Zookeeper集群架构:

  • Zookeeper的集群是有Leader的。
  • Leader宕机后,Zookeeper集群不会对外提供功能。
  • Zookeeper内部会存在投票机制,重新选举一个Leader。
  • Leader可以执行读写的操作。
  • Slave可以执行读的操作。

Zookeeper集群节点的解决:

  • Leader:
  • 执行处理读和写的操作。
  • Leader是唯一可以处理写操作的, 并且在执行写操作时,会根据一个FIFO的队列来保证写数据的顺序性。
  • 其他节点的唯一调度者。
  • Follower:
  • 执行读操作。
  • 在执行写操作时,进行投票。
  • 在重新选举Leader时,会参与投票。
  • Observer:
  • 执行读操作。
  • Looking:
  • 在Zookeeper节点刚刚启动时,寻找Leader。

Zookeeper集群的选举策略:

  • 选举数据最新的节点,根据数据的zxid判断。
  • 如果zxid相同,根据myid决定Leader。
1.6 搭建Zookeeper集群
# 当前3.4.14的版本, 不需要指定;2181,如果采用最新zookeeper,需要添加;2181
version: "3.1"
services:
  zk1:
    image: 10.0.134.175:5000/zookeeper:3.4.14
    container_name: zk1
    restart: always
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=zk1:2888:3888 server.2=zk2:2888:3888 server.3=zk3:2888:3888 
  zk2:
    image: 10.0.134.175:5000/zookeeper:3.4.14
    container_name: zk2
    restart: always
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zk1:2888:3888 server.2=zk2:2888:3888 server.3=zk3:2888:3888 
  zk3:
    image: 10.0.134.175:5000/zookeeper:3.4.14
    container_name: zk3
    restart: always
    ports:
      - 2183:2181
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zk1:2888:3888 server.2=zk2:2888:3888 server.3=zk3:2888:3888
1.7 Java操作Zookeeper
  • 导入依赖

<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>

  • Java连接Zookeeper

public static CuratorFramework cf(){
//1. 指定重试策略   3秒重试一次,一共重试2次.
RetryPolicy retry = new ExponentialBackoffRetry(1000,2);

//2. 成功构建出链接Zookeeper的对象
CuratorFramework cf = CuratorFrameworkFactory.builder()
.connectString("10.0.131.23:2181,10.0.131.23:2182,10.0.131.23:2183")
.retryPolicy(retry)
.build();

//3. 开启cf
cf.start();

//4. 返回
return cf;

}

  • Java操作Zookeeper

public class Demo1 {

@Test
 public void getChildren() throws Exception {
 CuratorFramework cf = ZkUtil.cf();List znodeList = cf.getChildren().forPath("/");
for (String s : znodeList) {
 System.out.println(s);
 }cf.close();
 }@Test
 public void create() throws Exception {
 CuratorFramework cf = ZkUtil.cf();cf.create().withMode(CreateMode.PERSISTENT).forPath("/qf",“哈哈哈”.getBytes());
cf.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/qf2",“嘿嘿嘿”.getBytes());
cf.create().withMode(CreateMode.EPHEMERAL).forPath("/qf3",“看不见我”.getBytes());
cf.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/qf4",“看不见我”.getBytes());
cf.close();
 }@Test
 public void getData() throws Exception {
 CuratorFramework cf = ZkUtil.cf();byte[] bytes = cf.getData().forPath("/qf");
 System.out.println(new String(bytes,“UTF-8”));cf.close();
 }@Test
public void setData() throws Exception {
CuratorFramework cf = ZkUtil.cf();

cf.setData().forPath("/qf","嘻嘻嘻".getBytes());

cf.delete().deletingChildrenIfNeeded().forPath("/qf20000000002");

Stat stat = cf.checkExists().forPath("/cluster");
System.out.println(stat);

cf.close();
}



}


  • Zookeeper的监听通知机制

@Test
public void listener() throws Exception {
CuratorFramework cf = ZkUtil.cf();

NodeCache nodeCache = new NodeCache(cf,"/qf");
nodeCache.getListenable().addListener(new NodeCacheListener() {
 @Override
 public void nodeChanged() throws Exception {
 // 在监听的节点改变后,获取节点信息
 byte[] data = nodeCache.getCurrentData().getData();
 String path = nodeCache.getCurrentData().getPath();
 Stat stat = nodeCache.getCurrentData().getStat();
 System.out.println(“监听的是:” + path + ",现在数据为: " + new String(data,“UTF-8”) + ",当前节点状态信息: " + stat );
 }
 });// !!!开始监听!!!
 nodeCache.start();
 System.out.println(“开始监听!!!”);System.in.read();
cf.close();
 }