zookeeper学习笔记

一、简介

1.zookeeper是一个开源的分布式服务协同系统,后来Apache接管。
2.集中管理不挑容易管理的分布式服务,组成一个高效可靠的集群服务。
3.集群服务通过zookeeper客户端连接zookeeper服务器,建立的连接为长连接(socket)
4.基本特征
  • 节点名称和节点value,路径必须保证唯一,不允许重复
  • 每个节点都会有事件通知,当节点发生任何变化都可以获取信息
5.应用场景
  • 分布式锁
  • Dubbo注册中心(zk)
  • 分布式配置中心disconfig
  • 分布式消息中间件
  • 发布订阅(事件通知)
  • Master选举

二、docker安装zookeeper

三、zookeeper简单使用

1.docker安装zookeeper

①docker pull zookeeper
②docker run --privileged=true -d --name zookeeper --publish 2181:2181 -d zookeeper:latest
③docker ps 查看是否安装成功

2.常用命令

①启动zookeeper,默认端口2181
②docker启动:docker run --name zookeeper -p 2181:2181 --restart always -d zookeeper

./zkServer.sh start

②命令模式远程连接zookeeper

./zkServer.sh [-server zookeeperip:port]
命令描述
ls/ls2 path列出当前目录全部子目录,ls2会多包含一些状态信息
create path data创建持久znode,存放数据data
create -e path data创建临时znode,存放数据data
create -s -e path data在znode下创建临时顺序节点
get path获取znode存储的数据
set path data[version]给znode赋值
delete path [version]删除znode
3.使用本地ZooInspector工具连接

①进入D:\Work\ZooInspector\build目录在cmd执行jar。

java -jar zookeeper-dev-ZooInspector.jar
4.java语客户端连接zookeeper

注意:先创建父节点,再创建子节点。
①添加pom依赖

 <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.8</version>
 </dependency>

②编写实现代码

public class Test01 {
    //参数1:连接地址
    private static final String CONNECTSTRING = "192.168.64.129:2181";
    //参数2:zk超时时间
    private static final int TIMEOUT = 5000;

    //参数3:事件通知
    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
        //zk核心节点+事件通知
        //节点路径和节点value
        /*
         * 参数1:连接地址
         * 参数2:zk超时时间
         * 参数3:事件通知
         * */
        ZooKeeper zooKeeper = new ZooKeeper(CONNECTSTRING, TIMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                Event.KeeperState state = watchedEvent.getState();
                if (state == Event.KeeperState.SyncConnected) {
                    System.out.println("连接成功");
                }
            }
        });
        //创建节点
        /*
         * 参数1:路径名称
         * 参数2:节点value
         * 参数3:节点权限acl
         * 参数4:节点类型(临时和持久)
         * */
        String s = zooKeeper.create("/test", "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println(s);
        zooKeeper.close();
    }
}
5.Countdown计算器优化代码
//创建CountDownLatch 
private static CountDownLatch countDownLatch = new CountDownLatch(1);
//连接成功后减1 
countDownLatch.countDown();
//计数器结果必须为0的情况下才继续执行
countDownLatch.await();
6.Zookeeper四种节点类型

①临时节点,会话关闭时就自动消失(CreateMode.PERSISTENT)
②持久节点,永久持久存活放到硬盘(CreateMode.EPHEMERAL)
③临时有序号节点(CreateMode.PERSISTENT_SEQUENTAIL)
④持久有序号节点

7.ACL权限控制

①world:默认方式,没有限制都可以访问。
②auth:代表已经认证通过的用户
③digest:使用账号密码方式认证,企业系统常用。
④ip:使用ip地址认证。
添加账号权限创建节点:

public class Test01 {
    //参数1:连接地址
    private static final String CONNECTSTRING = "192.168.64.129:2181";
    //参数2:zk超时时间
    private static final int TIMEOUT = 5000;
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    //参数3:事件通知
    public static void main(String[] args) throws IOException, KeeperException, InterruptedException, NoSuchAlgorithmException {
        //zk核心节点+事件通知
        //节点路径和节点value
        /*
         * 参数1:连接地址
         * 参数2:zk超时时间
         * 参数3:事件通知
         * */
        ZooKeeper zooKeeper = new ZooKeeper(CONNECTSTRING, TIMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                Event.KeeperState state = watchedEvent.getState();
                if (state == Event.KeeperState.SyncConnected) {
                    System.out.println("连接成功");
                    countDownLatch.countDown();
                }
            }
        });
        //计数器结果必须为0的情况下才继续执行
        countDownLatch.await();
        //创建账号权限admin可以实现读写操作
        Id id1 = new Id("digest", DigestAuthenticationProvider.generateDigest("admin:admin123"));
        ACL acl1 = new ACL(ZooDefs.Perms.ALL,id1);
        //创建权限guest只允许读操作
        Id id2 = new Id("digest", DigestAuthenticationProvider.generateDigest("guest:guest123"));
        ACL acl2 = new ACL(ZooDefs.Perms.READ,id2);
        //添加该账号
        ArrayList<ACL> aces = new ArrayList<ACL>();
        aces.add(acl1);
        aces.add(acl2);
        //创建节点
        /*
         * 参数1:路径名称
         * 参数2:节点value
         * 参数3:节点权限acl
         * 参数4:节点类型(临时和持久)
         * */
        String s = zooKeeper.create("/test", "test_acl".getBytes(), aces, CreateMode.PERSISTENT);
        System.out.println(s);
        zooKeeper.close();
    }

获取节点内容:

public class Test012 {
    //参数1:连接地址
    private static final String CONNECTSTRING = "192.168.64.129:2181";
    //参数2:zk超时时间
    private static final int TIMEOUT = 5000;
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    //参数3:事件通知
    public static void main(String[] args) throws IOException, KeeperException, InterruptedException, NoSuchAlgorithmException {
        //zk核心节点+事件通知
        //节点路径和节点value
        /*
         * 参数1:连接地址
         * 参数2:zk超时时间
         * 参数3:事件通知
         * */
        ZooKeeper zooKeeper = new ZooKeeper(CONNECTSTRING, TIMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                Event.KeeperState state = watchedEvent.getState();
                if (state == Event.KeeperState.SyncConnected) {
                    System.out.println("连接成功");
                    countDownLatch.countDown();
                }
            }
        });
        //计数器结果必须为0的情况下才继续执行
        countDownLatch.await();

        //设置连接账号
        zooKeeper.addAuthInfo("digest","guest:guest123".getBytes());

        //获取节点内容
        byte[] bytes = zooKeeper.getData("/test", null, new Stat());
        System.out.println(new String(bytes));

    }
8.服务注册

在springboot项目中添加如下代码:

@Component
public class ApplicationRunnerImpl implements ApplicationRunner {
    @Value("${server.port}")
    private String serverPort;
    //参数1:连接地址
    private static final String CONNECTSTRING = "192.168.64.129:2181";
    //参数2:zk超时时间
    private static final int TIMEOUT = 50000;
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        ZooKeeper zooKeeper = new ZooKeeper(CONNECTSTRING, TIMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                Event.KeeperState state = watchedEvent.getState();
                if (state == Event.KeeperState.SyncConnected) {
                    System.out.println("连接成功");
                    countDownLatch.countDown();
                }
            }
        });
        //计数器结果必须为0的情况下才继续执行
        countDownLatch.await();
        //1.判断父节点是否存在
        String path = "/test-service";
        Stat exists = zooKeeper.exists("service", null);
        //2.创建子节点
        if (exists == null) {
            //父节点不存在
            zooKeeper.create(path,"service".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        //实现服务注册
        String path1 = "http://192.168.64.1:" + serverPort;
        zooKeeper.create(path + "/" + serverPort,path1.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        System.out.println("服务注册成功");
    }
9.服务发现
public class Test0123 {
    //参数1:连接地址
    private static final String CONNECTSTRING = "192.168.64.129:2181";
    //参数2:zk超时时间
    private static final int TIMEOUT = 5000;
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    //参数3:事件通知
    public static void main(String[] args) throws IOException, KeeperException, InterruptedException, NoSuchAlgorithmException {
        ZooKeeper zooKeeper = new ZooKeeper(CONNECTSTRING, TIMEOUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                Event.KeeperState state = watchedEvent.getState();
                if (state == Event.KeeperState.SyncConnected) {
                    System.out.println("连接成功");
                    countDownLatch.countDown();
                }
            }
        });
        //计数器结果必须为0的情况下才继续执行
        countDownLatch.await();
        String path = "/test";
        List<String> children = zooKeeper.getChildren(path, null, new Stat());
        for (int i = 0; i < children.size(); i++) {
            String pathChildren = path + "/" + children.get(i);
            byte[] data = zooKeeper.getData(pathChildren, null, new Stat());
            System.out.println("服务地址" + new String(data));
        }
    }
}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐