Zookeeper学习总结

初识zookeeper

zookeeper的基本概念:

zookeeper的安装与配置

参见zookeeper的安装与配置(转黑马官方)_chaofengdev的博客-CSDN博客

zookeeper命令操作

数据模型

客户端常用命令

服务端常用命令

zookeeper java api操作

curator介绍

curator常用api

package com.itheima;
​
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
​
import java.nio.charset.StandardCharsets;
import java.util.List;
​
public class curatorTest {
    //提升作用域
    CuratorFramework client;
//==============================================create=========================================================================
    /*
    建立连接
     */
    @Test
    public void testConnect1(){
        //获取zookeeper client对象的两种方式。
        //1.第一种方式
        /*
        connectString – list of servers to connect to 连接字符串,zkserver的地址端口 “192.168.200.154:2181”
        sessionTimeoutMs – session timeout 会话超时时间
        connectionTimeoutMs – connection timeout 连接超时时间
        retryPolicy – retry policy to use 重试策略
         */
        //重试策略对象
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        //获取client对象(CuratorFramework)
        client = CuratorFrameworkFactory.newClient("192.168.200.154:2181", 60 * 1000, 15 * 1000, retryPolicy);
        //开启连接
        client.start();
    }
​
    @Before
    public void testConnect2(){
        //2.第二种方式
        //链式编程
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        client = CuratorFrameworkFactory.builder().connectString("192.168.200.154:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy).namespace("itheima").build();//使用名称空间
        client.start();
    }
​
    //创建结点:持久、临时、顺序、数据
    //1.基本创建
    //2.创建结点,带有数据
    //3.设置结点类型
    //4.创建多级结点
    @Test
    public void testCreate1() throws Exception {
        //1.基本创建
        //创建结点时没有指定结点的数据,会默认存储客户端的ip地址
        String path = client.create().forPath("/app22");
        System.out.println(path);
    }
​
    @Test
    public void testCreate2() throws Exception {
        //2.创建结点,带有数据
        String path = client.create().forPath("/app2", "zifushuzu".getBytes(StandardCharsets.UTF_8));
        System.out.println(path);
    }
​
    @Test
    public void testCreate3() throws Exception {
        //3.设置结点类型
        String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3", "hello".getBytes(StandardCharsets.UTF_8));
        System.out.println(path);
    }
​
    @Test
    public void testCreate4() throws Exception {
        //4.创建多级结点
        String path = client.create().creatingParentContainersIfNeeded().forPath("/app4/p1","nihaoya".getBytes(StandardCharsets.UTF_8));
        System.out.println(path);
    }
​
    @After
    public void close(){
        if(client!=null){
            client.close();
        }
    }
​
    //==================================================get================================================================
​
    /**
     * 查询结点:
     * 1.查询结点数据 get
     * 2.查询结点信息 ls
     * 3.查询结点状态信息 ls -s
     */
    @Test
    public void testGet1() throws Exception {
        //1.查询结点数据 get
        byte[] data = client.getData().forPath("/app4/p1");
        System.out.println(new String(data));
    }
​
    @Test
    public void testGet2() throws Exception{
        //2.查询结点信息 ls
        List<String> child = client.getChildren().forPath("/");
        System.out.println(child);
    }
​
    @Test
    public void testGet3() throws Exception{
        //3.查询结点状态信息 ls -s
        Stat stat = new Stat();
        System.out.println(stat);//查询前为空
        client.getData().storingStatIn(stat).forPath("/app4");
        System.out.println(stat);//查询结点的状态信息
    }
    //===============================================set===================================================================
​
    /**
     * 修改数据
     * 1.修改数据
     * 2.根据版本修改
     *      version是查询出来的,是为了实现原子性操作(锁的机制)
     *      Each time a znode's data changes, the version number increases. For instance, whenever a client retrieves data it also receives the version of the data.
     *      每次 znode 的数据发生更改时,版本号都会增加。例如,每当客户端检索数据时,它也会收到数据的版本。
     * @throws Exception
     */
    @Test
    public void testSet() throws Exception {
        Stat stat = client.setData().forPath("/app1", "itcast".getBytes(StandardCharsets.UTF_8));
        System.out.println(stat);
    }
​
    @Test
    public void testSetForVersion() throws Exception {
        //查询结点相关信息
        Stat stat = new Stat();
        client.getData().storingStatIn(stat).forPath("/app1");
        //查询接地那信息中的版本信息version(本质上是锁的机制)
        int version = stat.getVersion();
        Stat stat1 = client.setData().withVersion(version).forPath("/app1","haha".getBytes());
    }
​
    //==========================================delete=====================================================================
​
    /**
     * 删除结点
     * 1.删除单个结点
     * 2.删除带有子节点的结点
     * 3.必须成功删除
     * 4.回调
     */
    @Test
    public void testDelete() throws Exception {
        //1.删除单个结点
        client.delete().forPath("/app1");
    }
​
    @Test
    public void testDelete2() throws Exception {
        //2.删除带有子节点的结点
        client.delete().deletingChildrenIfNeeded().forPath("/app4");
    }
​
    @Test
    public void testDelete3() throws Exception{
        //3.必须成功删除(为了防止网络抖动,本质就是重试几次)
        client.delete().guaranteed().forPath("/app2");
    }
​
    @Test
    public void testDelete4() throws Exception {
        //4.回调(一知半解)
        client.delete().guaranteed().inBackground(new BackgroundCallback() {
            @Override
            public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                System.out.println("delete");//提示删除完成
                System.out.println(event);//相关信息
            }
        }).forPath("app4");
    }
}
​
package com.itheima;
​
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
​
import java.nio.charset.StandardCharsets;
import java.util.List;
​
public class curatorWatcherTest {
    //提升作用域
    CuratorFramework client;
//==============================================create=========================================================================
    /*
    建立连接
     */
    @Test
    public void testConnect1(){
        //获取zookeeper client对象的两种方式。
        //1.第一种方式
        /*
        connectString – list of servers to connect to 连接字符串,zkserver的地址端口 “192.168.200.154:2181”
        sessionTimeoutMs – session timeout 会话超时时间
        connectionTimeoutMs – connection timeout 连接超时时间
        retryPolicy – retry policy to use 重试策略
         */
        //重试策略对象
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        //获取client对象(CuratorFramework)
        client = CuratorFrameworkFactory.newClient("192.168.200.154:2181", 60 * 1000, 15 * 1000, retryPolicy);
        //开启连接
        client.start();
    }
​
    @Before
    public void testConnect2(){
        //2.第二种方式
        //链式编程
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        client = CuratorFrameworkFactory.builder().connectString("192.168.200.154:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy).namespace("itheima").build();//使用名称空间
        client.start();
    }
​
    //创建结点:持久、临时、顺序、数据
    //1.基本创建
    //2.创建结点,带有数据
    //3.设置结点类型
    //4.创建多级结点
    @Test
    public void testCreate1() throws Exception {
        //1.基本创建
        //创建结点时没有指定结点的数据,会默认存储客户端的ip地址
        String path = client.create().forPath("/app22");
        System.out.println(path);
    }
​
    @Test
    public void testCreate2() throws Exception {
        //2.创建结点,带有数据
        String path = client.create().forPath("/app2", "zifushuzu".getBytes(StandardCharsets.UTF_8));
        System.out.println(path);
    }
​
    @Test
    public void testCreate3() throws Exception {
        //3.设置结点类型
        String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3", "hello".getBytes(StandardCharsets.UTF_8));
        System.out.println(path);
    }
​
    @Test
    public void testCreate4() throws Exception {
        //4.创建多级结点
        String path = client.create().creatingParentContainersIfNeeded().forPath("/app4/p1","nihaoya".getBytes(StandardCharsets.UTF_8));
        System.out.println(path);
    }
​
    @After
    public void close(){
        if(client!=null){
            client.close();
        }
    }
​
    //==================================================get================================================================
​
    /**
     * 查询结点:
     * 1.查询结点数据 get
     * 2.查询结点信息 ls
     * 3.查询结点状态信息 ls -s
     */
    @Test
    public void testGet1() throws Exception {
        //1.查询结点数据 get
        byte[] data = client.getData().forPath("/app4/p1");
        System.out.println(new String(data));
    }
​
    @Test
    public void testGet2() throws Exception{
        //2.查询结点信息 ls
        List<String> child = client.getChildren().forPath("/");
        System.out.println(child);
    }
​
    @Test
    public void testGet3() throws Exception{
        //3.查询结点状态信息 ls -s
        Stat stat = new Stat();
        System.out.println(stat);//查询前为空
        client.getData().storingStatIn(stat).forPath("/app4");
        System.out.println(stat);//查询结点的状态信息
    }
    //===============================================set===================================================================
​
    /**
     * 修改数据
     * 1.修改数据
     * 2.根据版本修改
     *      version是查询出来的,是为了实现原子性操作(锁的机制)
     *      Each time a znode's data changes, the version number increases. For instance, whenever a client retrieves data it also receives the version of the data.
     *      每次 znode 的数据发生更改时,版本号都会增加。例如,每当客户端检索数据时,它也会收到数据的版本。
     * @throws Exception
     */
    @Test
    public void testSet() throws Exception {
        Stat stat = client.setData().forPath("/app1", "itcast".getBytes(StandardCharsets.UTF_8));
        System.out.println(stat);
    }
​
    @Test
    public void testSetForVersion() throws Exception {
        //查询结点相关信息
        Stat stat = new Stat();
        client.getData().storingStatIn(stat).forPath("/app1");
        //查询接地那信息中的版本信息version(本质上是锁的机制)
        int version = stat.getVersion();
        Stat stat1 = client.setData().withVersion(version).forPath("/app1","haha".getBytes());
    }
​
    //==========================================delete=====================================================================
​
    /**
     * 删除结点
     * 1.删除单个结点
     * 2.删除带有子节点的结点
     * 3.必须成功删除
     * 4.回调
     */
    @Test
    public void testDelete() throws Exception {
        //1.删除单个结点
        client.delete().forPath("/app1");
    }
​
    @Test
    public void testDelete2() throws Exception {
        //2.删除带有子节点的结点
        client.delete().deletingChildrenIfNeeded().forPath("/app4");
    }
​
    @Test
    public void testDelete3() throws Exception{
        //3.必须成功删除(为了防止网络抖动,本质就是重试几次)
        client.delete().guaranteed().forPath("/app2");
    }
​
    @Test
    public void testDelete4() throws Exception {
        //4.回调(一知半解)
        client.delete().guaranteed().inBackground(new BackgroundCallback() {
            @Override
            public void processResult(CuratorFramework client, CuratorEvent event) throws Exception {
                System.out.println("delete");//提示删除完成
                System.out.println(event);//相关信息
            }
        }).forPath("app4");
    }
​
​
    //======================================watch========================================================================
    /**
     * 给指定一个结点的*子节点*注册监听器
     *
     */
    @Test
    public void testPathChildrenCache() throws Exception{
        //1.创建监听对象
        PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app2", true);
​
        //2.绑定监听器
        pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                System.out.println("child node has changed...");
                System.out.println(event);
                //监听子节点的数据变更,并且拿到变更后的数据
                //1.获取数据类型
                PathChildrenCacheEvent.Type type = event.getType();
                //2.判断类型是否是update
                if(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                    //PathChildrenCacheEvent{type=CHILD_UPDATED, data=ChildData{path='/app2/p2', stat=192,209,1643545922168,1643546628992,2,0,0,0,3,0,192
                    //, data=[49, 49, 49]}}
                    System.out.println("child node update...");
                    byte[] data = event.getData().getData();//根据event的输出格式来理解此处代码
                    System.out.println(new String(data));
                }
            }
        });
​
        //3.开启监听器
        pathChildrenCache.start();
        while(true){
            //死循环
        }
    }
​
    @Test
    public void testNodeCache() throws Exception{
        //1.创建NodeCache对象
        NodeCache nodeCache = new NodeCache(client, "/app1");
        //2.注册监听-理解
        nodeCache.getListenable().addListener(new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                System.out.println("node has changed...");
                //获取修改结点后的数据
                byte[] data = nodeCache.getCurrentData().getData();
                System.out.println(new String(data));
            }
        });
        //3.开启监听,如果设置为true,开启监听时加载缓存数据。
        nodeCache.start(true);
        //死循环用于制造客户端一直连接并监听相关结点的情况
        //这里一直循环,表示客户端一直存活,服务端有响应会返回;
        //否则单元测试结束,表示客户端结束,服务端有结果也无法返回。
        while(true){
            //死循环
        }
    }
​
    //=========================================treeCache==================================================================
    @Test
    public void testTreeCache() throws Exception {
        //1.创建监听器
        TreeCache treeCache = new TreeCache(client, "/app2");
        //2.注册监听
        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                System.out.println("treeCache changed...");
                System.out.println(event);
            }
        });
        //3.开启监听
        treeCache.start();
        while (true) {
        }
    }
​
}
​

分布式锁

模拟12306

package com.itheima;
​
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
​
import java.util.concurrent.TimeUnit;
​
/**
 * 基于zookeeper实现分布式锁。
 * 基本原理参见:zookeeper分布式锁原理
 * 核心思想:当客户端要获取锁,创建结点;使用完锁,则删除结点;
 * 客户端获取锁时,在lock结点下创建*临时顺序结点*
 * 其他过程暂略。
 */
public class Ticket12306 implements Runnable{
    private int ticket = 100000000;//票数
    private InterProcessMutex interProcessMutex;//互斥锁
    CuratorFramework client;//客户端对象
    public Ticket12306() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
        client = CuratorFrameworkFactory.builder().connectString("192.168.200.154:2181")
                .sessionTimeoutMs(60 * 1000)
                .connectionTimeoutMs(15 * 1000)
                .retryPolicy(retryPolicy).namespace("itheima").build();//使用名称空间
        client.start();
        interProcessMutex = new InterProcessMutex(client,"/lock");
    }
​
    @Override
    public void run() {
        while(true){
            //加锁
            try {
                interProcessMutex.acquire(3, TimeUnit.SECONDS);
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName()+":"+ticket);
                    ticket--;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                //释放锁
                try {
                    interProcessMutex.release();//突然理解异常的用处了。
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
​
        }
    }
}
package com.itheima;
​
/**
 * 测试基于zookeeper实现的分布式锁
 */
public class lockTest {
    public static void main(String[] args) {
        Ticket12306 ticket12306 = new Ticket12306();
        //创建客户端
        Thread xiecheng = new Thread(ticket12306, "xiecheng");
        Thread feizhu = new Thread(ticket12306, "feizhu");
        //开启两个线程来运行买票服务
        xiecheng.start();
        feizhu.start();
    }
}
​

zookeeper集群搭建

参见:搭建Zookeeper集群(转黑马官方,补充了一点可能遇到的小坑)_chaofengdev的博客-CSDN博客

zookeeper核心理论

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值