强大的Zookeeper

Zookeeper

Zookeeper的作用
  • Zookeeper可以作为注册中心,实现服务的注册与发现。
  • Zookeeper基于监听通知机制可以实现配置的统一管理。
  • Zookeeper可以基于他存储节点的特点,实现分布式锁。
  • Zookeeper可以作为很多中间件的集群统一协调管理。
安装Zookeeper

docker-compose.yml

version: "3.1"
services:
 zk:
  image: >daocloud.io/daocloud/zookeeper:latest
  restart: always
  container_name: zk
  ports:
    - 2181:2181
Zookeeper的架构

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

znode类型

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

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

Zookeeper常用命令

查询

# 查询当前节点下的全部子节点
ls 节点名称
# 例子 ls /

# 查询当前节点下的数据
get 节点名称
# 例子 get /zookeeper

创建节点

create [-s] [-e] znode名称 znode数据

# -s:sequence,有序节点
# -e:ephemeral,临时节点

修改节点数据

set znode名称 新数据

** 删除节点数据**

# 没有子节点的znode
delete znode名称

# 删除当前节点和全部的子节点
rmr znode名称
# rmr看版本,有的版本是deleteall
Zookeeper集群结构

Zookeeper集群架构

  • Zookeeper的集群是有Leader的。
  • Leader宕机后,Zookeeper集群不会对外提供功能。
  • Zookeeper内部会存在投票机制,重新选举一个Leader。
  • Zookeeper必须有master节点,不然无法正常工作(就是必须有两个及以上)
  • Leader可以执行读写的操作。
  • Slave可以执行读的操作。

Zookeeper集群节点的解决

  • Leader:
    • 执行处理读和写的操作。
    • Leader是唯一可以处理写操作的, 并且在执行写操作时,会根据一个FIFO的队列来保证写数据的顺序性。
    • 其他节点的唯一调度者。
  • Follower:
    • 执行读操作。
    • 在执行写操作时,进行投票。
    • 在重新选举Leader时,会参与投票。
  • Observer:
    • 执行读操作。
  • Looking:
    • 在Zookeeper节点刚刚启动时,寻找Leader。
Zookeeper投票策略
  • 每一个Zookeeper服务都会被分配一个全局唯一的myid,myid是一个数字。
  • Zookeeper在执行写数据时,每一个节点都有一个自己的FIFO的队列。保证写每一个数据的时候,顺序是不会乱的,Zookeeper还会给每一个数据分配一个全局唯一的zxid,数据越新zxid就越大。

选举Leader

  • 选举出zxid最大的节点作为Leader。
  • 在zxid相同的节点中,选举出一个myid最大的节点,作为Leader。
搭建Zookeeper集群

ZOO_SERVERS: server(固定的).1(myid)=zk1(服务名,上边那个,不是container_name):2888(集群通讯端口):3888(集群投票端口);2181(容器内端口号)

version: "3.1"
services:
 zk1:
   image: zookeeper
   restart: always
   container_name: zk1
   ports:
     - 2181:2181
   environment:
     ZOO_MY_ID: 1
     ZOO_SERVERS: server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181
 zk2:
   image: zookeeper
   restart: always
   container_name: zk2
   ports:
     - 2182:2181
   environment:
     ZOO_MY_ID: 2
     ZOO_SERVERS: server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181
 zk3:
   image: zookeeper
   restart: always
   container_name: zk3
   ports:
     - 2183:2181
   environment:
     ZOO_MY_ID: 3
     ZOO_SERVERS: server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181
Java连接Zookeeper

导入依赖

<dependencies>
   <dependency>
       <groupId>org.apache.zookeeper</groupId>
       <artifactId>zookeeper</artifactId>
       <version>3.6.0</version>
   </dependency>

   <dependency>
       <groupId>org.apache.curator</groupId>
       <artifactId>curator-recipes</artifactId>
       <version>4.0.1</version>
   </dependency>

   <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>4.12</version>
   </dependency>
</dependencies>

** 编写连接Zookeeper集群的工具类**

public class ZkUtil {

   public static CuratorFramework cf(){
   	// 指定重试策略   3秒重试一次,一共重试2次
       RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,2);
       // 成功构建出链接Zookeeper的对象
       CuratorFramework cf = CuratorFrameworkFactory.builder()
               .connectString("192.168.199.109:2181,192.168.199.109:2182,192.168.199.109:2183")
               .retryPolicy(retryPolicy)
               .build();
		// 开启
       cf.start();
		// 返回
       return cf;
   }
}
Java操作Znode节点

查询

public class Demo2 {
   CuratorFramework cf = ZkUtil.cf();
   // 获取子节点
   @Test
   public void getChildren() throws Exception {
       List<String> strings = cf.getChildren().forPath("/");

       for (String string : strings) {
           System.out.println(string);
       }
   }
   // 获取节点数据
   @Test
   public void getData() throws Exception {
       byte[] bytes = cf.getData().forPath("/qf");
       System.out.println(new String(bytes,"UTF-8"));
   }
}

** 添加**

@Test
public void create() throws Exception {
   cf.create().withMode(CreateMode.PERSISTENT).forPath("/qf2","uuuu".getBytes());
}
**修改**
```java
@Test
public void update() throws Exception {
   cf.setData().forPath("/qf2","oooo".getBytes());
}

** 删除**

@Test
public void delete() throws Exception {
  cf.delete().deletingChildrenIfNeeded().forPath("/qf2");
}

查看znode的状态

@Test
public void stat() throws Exception {
   Stat stat = cf.checkExists().forPath("/qf");
   System.out.println(stat);
}
监听通知机制
public class Demo3 {

   CuratorFramework cf = ZkUtil.cf();
   @Test
   public void listen() throws Exception {
       //1. 创建NodeCache对象,指定要监听的znode
       NodeCache nodeCache = new NodeCache(cf,"/qf");
       nodeCache.start();

       //2. 添加一个监听器
       nodeCache.getListenable().addListener(new NodeCacheListener() {
           @Override
           public void nodeChanged() throws Exception {
               byte[] data = nodeCache.getCurrentData().getData();
               Stat stat = nodeCache.getCurrentData().getStat();
               String path = nodeCache.getCurrentData().getPath();

               System.out.println("监听的节点是:" + path);
               System.out.println("节点现在的数据是:" + new String(data,"UTF-8"));
             System.out.println("节点状态是:" + stat);

          }
       });

       System.out.println("开始监听!!");
      //3. System.in.read();
       System.in.read();
   }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值