Zookeeper学习笔记

Zookeeper

初始Zookeeper

在这里插入图片描述

Zookeeper的安装

  • JDK的安装
    https://blog.csdn.net/qq_42815754/article/details/82968464?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-82968464-blog-82926514.pc_relevant_aa2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-82968464-blog-82926514.pc_relevant_aa2&utm_relevant_index=3
  • zookeeper的安装

Zookeeper的命令操作

数据模型

在这里插入图片描述

服务端命令

  • 查看状态
    在这里插入图片描述
  • 关闭
    在这里插入图片描述
  • 启动
  • 在这里插入图片描述
  • 重启
    在这里插入图片描述

客户端命令

  • 启动客户端,连接服务端
./zkCli.sh -server 127.0.0.1:2181
  • 连接本机的服务端,无序添加-server参数
  • 退出命令
quit
  • 查看节点
ls

在这里插入图片描述
在这里插入图片描述

  • 创建与获取节点

在这里插入图片描述

  • 命令总结
    -在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

javaAPI的操作

  • cutator的介绍
    在这里插入图片描述

curator的连接

在这里插入图片描述

  • 使用CuratorFrameworkFactory工厂创建CuratorFramework方法
  • 指定参数
  • 两种方式实现连接
  • 使用newclient方法
 String connectstring="192.168.253.128:2181";
        int sessionTimeout=60*1000;
        int connnectionTimeout=3*1000;
        RetryPolicy retryPolicy=new ExponentialBackoffRetry(1000,2);
        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(connectstring, sessionTimeout, connnectionTimeout, retryPolicy);

//        CuratorFramework lmx = CuratorFrameworkFactory.builder().connectString(connectstring).connectionTimeoutMs(3000).
//                retryPolicy(retryPolicy).
//                namespace("lmx").build();
        curatorFramework.start();
  • 使用builder构造器
        String connectstring="192.168.253.128:2181";
        int sessionTimeout=60*1000;
        int connnectionTimeout=3*1000;
        RetryPolicy retryPolicy=new ExponentialBackoffRetry(1000,2);
//        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(connectstring, sessionTimeout, connnectionTimeout, retryPolicy);

        CuratorFramework lmx = CuratorFrameworkFactory.builder().connectString(connectstring).connectionTimeoutMs(3000).
                retryPolicy(retryPolicy).
                namespace("lmx").build();
        lmx.start();

**namespace参数:创建节点的根目录,下面创建节点的根目录是在lmx目录下创建,指定namespace可以省略不写根目录 **
在这里插入图片描述

节点的创建

  • 基本创建

    //
    //        如果不指定存储的数据,在该节点中存取的是ip地址
            String app = lmx.create().forPath("/app");
            System.out.println(app);

在这里插入图片描述

  • 创建节点,带有数据
String s = lmx.create().forPath("/app3", "李满祥".getBytes());
        System.out.println(s);

  • 创建多级节点,使用creatingParentsIfNeeded方法

String s = lmx.create().creatingParentsIfNeeded().forPath("/app4/person", "people".getBytes());
        System.out.println(s);
  • 设置节点的类型,使用withMode参数
String s = lmx.create().withMode(CreateMode.EPHEMERAL).forPath("s");
        
        System.out.println(s);


节点的查询

在这里插入图片描述

  • 查询节点内容
//        查询节点内容
        byte[] bytes = lmx.getData().forPath("/");
        System.out.println(new String(bytes));

	~~~
- 查询子节点
~~~java
//        查询子节点
        List<String> strings = lmx.getChildren().forPath("/");
        System.out.println(strings);
  • 查询节点的状态

//         查看节点的状态
        Stat stat = new Stat();
        byte[] bytes1 = lmx.getData().storingStatIn(stat).forPath("/app");
        System.out.println(stat);

修改节点数据

  • 修改数据
Stat stat = lmx.setData().forPath("/app", "lmx".getBytes());
        System.out.println(new String(lmx.getData().forPath("/app")));
  • 根据版本状态,防止多线程或者多用户去修改,在实际开发过程中使用这种方法
//        根据版本修改
       Stat stat = new Stat();
       lmx.getData().storingStatIn(stat).forPath("/app");
//        获取版本号
       int version = stat.getVersion();

       lmx.setData().withVersion(version).forPath("/app","wuxiang".getBytes());

删除节点

  • 删除单个节点
lmx.delete().forPath("/app");
  • 删除带有子节点的节点 deletingChildrenIfNeeded() 函数

lmx.delete().deletingChildrenIfNeeded().forPath("/app");
  • 必须成功删除 guaranteed() 函数
lmx.delete().guaranteed().deletingChildrenIfNeeded().forPath("/app");

  • 回调
lmx.delete().guaranteed().deletingChildrenIfNeeded().inBackground(new BackgroundCallback() {
            @Override
            public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
                System.out.println("我被删除了");
                System.out.println(curatorEvent);
            }
        }).forPath("/app1");

Watch事件的监听

  • 概念

    • ZooKeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通
      知到感兴趣的客户端上去,该机制是ZooKeeper实现分布式协调服务的重要特性。
    • ZooKeeper中引入了Watcher机制来实现了发布/订阅功能能,能够让多个订阅者同时监听某一个对象,当一个对象自身
      状态变化时,会通知所有订阅者。
    • ZooKeeper原生支持通过注册Watcher来进行事件监听
      但是其使用并不是特别方便
      需要开发人员自己反复注册Watcher,比较率琐。
    • Curator引入了Cache来实现对ZooKeeper服务端事件的监听。
  • ZooKeeper提供了三种watcher:

    • NodeCache:只是监听某一个特定的节点
    • PathChildrenCache:监控一个ZNode的子节点
    • TreeCache:可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCachel的组合

NodeCache的监听

  • 实现某一个节点的监听
//        dataIsCompressed参数的意思是否压缩数据
        NodeCache nodeCache = new NodeCache(clinet, "/test");

//        设置监听器

        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                System.out.println("节点发生了改变");
                try {
                    byte[] bytes = nodeCache.getClient().getData().forPath(nodeCache.getPath());
                    System.out.println(new String(bytes));
                }catch (Exception e){
                    System.out.println("节点发生异常,可能被删除");
                    e.printStackTrace();

                }

            }
        });

        nodeCache.start();
//        clinet.getCuratorListenable().removeListener(change);
        while (true) {

        }
while (true) {

        }模拟的是微服务启动

PathChildrenCache的监听

  • 监听该节点下面的子节点数据
 clinet.delete().guaranteed().forPath("/test1/p1");
        clinet.delete().guaranteed().forPath("/test1/p2");

        clinet.create().creatingParentsIfNeeded().forPath("/test1/p1");
        clinet.create().creatingParentsIfNeeded().forPath("/test1/p2");

        PathChildrenCache pathChildrenCache = new PathChildrenCache(clinet,"/test1",true);

        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
                System.out.println("节点发生了改变");
                if (pathChildrenCacheEvent.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                    byte[] data = pathChildrenCacheEvent.getData().getData();
                    System.out.println(new String(data));
                }
            }
        });

        pathChildrenCache.start();

//         模拟微服务的启动状态
        while (true){

        }

TreeCache的监听

  • 可以监听该节点及子节点的数据
TreeCache treeCache = new TreeCache(clinet,"/test1");

       treeCache.getListenable().addListener(new TreeCacheListener() {
           @Override
           public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
               System.out.println("节点改变了");
               if (treeCacheEvent.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)){
                   System.out.println(new String(treeCacheEvent.getData().getData()));
               }
           }
       });

       treeCache.start();

//         模拟微服务的启动状态
       while (true){

       }

分布式锁

概念

  • 在我们进行单机应用开发,涉及并发同步的时候,我们往往采用synchronized或者Lock的方式来解决多线程间的代码同步问题,
    这时多线程的运行都是在同一个VM之下,没有任何问题。
  • 但当我们的应用是分布式集群工作的情况下,属于多VM下的工作环境,跨VM之间已经无法通过多线程的锁解决同步问题。
  • 那么就需要一种更加高级的锁机制,来处理跨机器的进程之间的数据同步问题一这就是分布式锁。
  • 在这里插入图片描述
    在这里插入图片描述

zk实现分布式锁的原理

  • 核心思想:当客户端要获取锁,则创建节点,使用完锁,则删除该点。
    在这里插入图片描述
    在这里插入图片描述

curator实现分布式锁

在这里插入图片描述在这里插入图片描述

  • 模仿买票的多线程
public class Ticket12306 implements Runnable {
    private int ticket = 10;

    private InterProcessMutex interProcessMutex;

    public Ticket12306() {
        RetryPolicy retryPolicy=new ExponentialBackoffRetry(3*1000,10);
        CuratorFramework build = CuratorFrameworkFactory.builder().connectString("192.168.253.128:2181")
                .connectionTimeoutMs(3 * 1000)
                .retryPolicy(retryPolicy)
                .build();
        build.start();

        interProcessMutex=new InterProcessMutex(build,"/lock");

    }

//    @SneakyThrows
    @Override
    public void run() {


        while (true) {
            try {
                interProcessMutex.acquire(3, TimeUnit.SECONDS);//获取锁的时间;
//            获取锁
                if (ticket>0){
                    System.out.println(Thread.currentThread().getName() + "卖票了" + ticket);
                    ticket--;
                }
                Thread.sleep(2000);

            }catch (Exception e){
                e.printStackTrace();
            }finally {
                try {
                    interProcessMutex.release();
                    if (ticket==0){
                      return;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

//            释放锁
        }

//        释放锁
    }
}

  • 关键代码
  • 获取锁与释放锁
interProcessMutex.acquire(3, TimeUnit.SECONDS);//获取锁的时间;
interProcessMutex.release();
  • 实现卖票

  Ticket12306 ticket12306 = new Ticket12306();
        Ticket12306 ticket123061 = new Ticket12306();

        Thread t1=new Thread(ticket12306,"携程");
        Thread t2=new Thread(ticket12306,"飞猪");
        t1.start();
        t2.start();

zk集群

在这里插入图片描述

集群角色

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值