zookeeper集群搭建和API使用

一、vmware设置虚拟机centeros的ip

1、设置vm属性

先设置NAT模式

在这里插入图片描述

点击菜单栏编辑

在这里插入图片描述

记录子网网关地址

在这里插入图片描述

在这里插入图片描述

2、修改linux配置

【1】修改linux ip地址

vi /etc/sysconfig/network-scripts/ifcfg-ens* (*根据实际情况不同,本文为ens33)

vi /etc/sysconfig/network-scripts/ifcfg-ens33

BOOTPROTO=static
IPADDR=192.168.220.10
NETMASK=255.255.255.0
GATEWAY=192.168.220.2
ONBOOT=yes

ONBOOT:是指系统启动时是否激活网卡,默认为no,设置为yes,表示开机启动时激活网卡。

BOOTPROTO:网络分配方式,静态。(一定记得修改为Static,否则无法连通网络)

IPPADDR:手动指定ip地址。

NETMASK:子网掩码。

GATEWAY:网关ip。

【2】设置主机名

vim /etc/hostname

【3】重启

重启网卡,使用service network restart命令重启网卡。

重启虚拟机 reboot

3、更改本地配置

在这里插入图片描述

在这里插入图片描述

4、验证

通过xshell ping下linuxip

在这里插入图片描述

连接成功

在这里插入图片描述

连接外网成功

在这里插入图片描述

二、安装zookeeper

1、下载zookeeper

wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.6.1/apache-zookeeper-3.6.1-bin.tar.gz

在这里插入图片描述

2、解压到opt目录下

tar -zxvf apache-zookeeper-3.6.1-bin.tar.gz -C /opt

在这里插入图片描述

3、给zk版本目录建立软连接

ln -s apache-zookeeper-3.6.1-bin/ zookeeper

4、设置zookeeper的path路径

vi /etc/profile

加入环境变量

export ZK_HOME=/opt/zookeeper

export PATH= Z K H O M E / b i n : ZK_HOME/bin: ZKHOME/bin:PATH

应用path

source /etc/profile

5、修改配置文件

cd /opt/zookeeper

复制一份配置文件

cp zoo_sample.cfg zoo.cfg

修改配置

a 修改数据地址

dataDir=/usr/data/zookeeper

server.1=192.168.220.10:2888:3888

server.2=192.168.220.11:2888:3888

server.3=192.168.220.12:2888:3888

server.4=192.168.220.12:2888:3888:observer

在这里插入图片描述

6、启动zk

zkServer.sh start

在这里插入图片描述

zkServer.sh status

在这里插入图片描述

发现集群模式并未真正运行

7、复制虚拟机

通过克隆的方式把集群中的zk2、zk3、zk4克隆出来

然后依次修改克隆出来的主机ip、hostname、conf

8、问题

a myid找不到

在dataDir路径/usr/data/zookeeper 下创建myid文件并设置myid

b java.net.NoRouteToHostException: No route to host (Host unreachable)

在这里插入图片描述

需要关闭防火墙

systemctl stop firewalld

9、启动

命令

zkServer.sh start

zkServer.sh restart

zkServer.sh status

zkServer.sh stop

结果

zkOS1

在这里插入图片描述

zkOS2

在这里插入图片描述

zkOS3

在这里插入图片描述

zkOS4

在这里插入图片描述

三、zk故障恢复

1、正常状态数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jdxHVbxu-1594306317993)(asserts/1590302120084.png)]

2、模拟leader宕机

leader是server2

在这里插入图片描述

zkServer3成为新的leader

重新启动zkSever2成为follower

在这里插入图片描述

四、zookeeper java客户端

1、zkClient

在使用ZooKeeper的Java客户端时,经常需要处理几个问题:重复注册watcher、session失效重连、异常处理。

​ 要解决上述的几个问题,可以自己解决,也可以采用第三方的java客户端来完成。这里就介绍一种常用的客户端zkclient,目前已经运用到了很多项目中,知名的有Dubbo、Kafka、Helix。

【1】依赖

<dependency>
     <groupId>org.apache.zookeeper</groupId>
     <artifactId>zookeeper</artifactId>
     <version>3.4.9</version>
 </dependency>
 <dependency>
     <groupId>com.github.sgroschupf</groupId>
     <artifactId>zkclient</artifactId>
     <version>0.1</version>
 </dependency>

【2】 增删改查

public class ZkClientBase {
    
    
 
    /** zookeeper地址 */
    static final String CONNECT_ADDR = "192.168.1.31:2181,192.168.1.32:2181,192.168.1.33:2181";
   
    /** session超时时间 */
    static final int SESSION_OUTTIME = 10000;//ms
 
    public static void main(String[] args) throws Exception {
    
    
        ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), SESSION_OUTTIME);
        //1. create and delete方法
 
        zkc.createEphemeral("/temp");
        zkc.createPersistent("/super/c1", true);
        Thread.sleep(10000);
        zkc.delete("/temp");
        zkc.deleteRecursive("/super");
 
        //2. 设置path和data 并且读取子节点和每个节点的内容
        zkc.createPersistent("/super", "1234");
        zkc.createPersistent("/super/c1", "c1内容");
        zkc.createPersistent("/super/c2", "c2内容");
        List<String> list = zkc.getChildren("/super");
        for(String p : list){
    
    
            System.out.println(p);
            String rp = "/super/" + p;
            String data = zkc.readData(rp);
            System.out.println("节点为:" + rp + ",内容为: " + data);
        }
 
        //3. 更新和判断节点是否存在
        zkc.writeData("/super/c1", "新内容");
        System.out.println(zkc.readData("/super/c1").toString());
        System.out.println(zkc.exists("/super/c1"));
 
//      4.递归删除/super内容
        zkc.deleteRecursive("/super");
    }
}

【3】注册节点监听器

(1) 订阅节点数据变化

监听节点数据变化、节点删除

public class ZkClientWatcher2 {
    
    
 
    /** zookeeper地址 */
    static final String CONNECT_ADDR = "192.168.1.31:2181,192.168.1.32:2181,192.168.1.33:2181";
    /** session超时时间 */
    static final int SESSION_OUTTIME = 10000;//ms
 
 
    public static void main(String[] args) throws Exception {
    
    
        ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), SESSION_OUTTIME);
 
        zkc.createPersistent("/super", "1234");
 
        //对父节点添加监听子节点变化。
        zkc.subscribeDataChanges("/super", new IZkDataListener() {
    
    
            @Override
            public void handleDataDeleted(String path) throws Exception {
    
    
                System.out.println("删除的节点为:" + path);
            }
 
            @Override
            public void handleDataChange(String path, Object data) throws Exception {
    
    
                System.out.println("变更的节点为:" + path + ", 变更内容为:" + data);
            }
        });
 
        Thread.sleep(3000);
        zkc.writeData("/super", "456", -1);
        Thread.sleep(1000);
 
        zkc.delete("/super");
        Thread.sleep(Integer.MAX_VALUE);
    }
}
(2)订阅子节点的变化

监听如下三种变化

  • 新增子节点

  • 减少子节点

  • 删除节点

    注意: 不监听节点内容的变化

public class ZkClientWatcher1 {
    
    
 
    /** zookeeper地址 */
    static final String CONNECT_ADDR = "192.168.1.31:2181,192.168.1.32:2181,192.168.1.33:2181";
    /** session超时时间 */
    static final int SESSION_OUTTIME = 10000;//ms
 
 
    public static void main(String[] args) throws Exception {
    
    
        ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), SESSION_OUTTIME);
 
        //对父节点添加监听子节点变化。
        zkc.subscribeChildChanges("/super", new IZkChildListener() {
    
    
            @Override
            public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
    
    
                System.out.println("parentPath: " + parentPath);
                System.out.println("currentChilds: " + currentChilds);
            }
        });
 
        Thread.sleep(3000);
 
        zkc.createPersistent("/super");
        Thread.sleep(1000);
 
        zkc.createPersistent("/super" + "/" + "c1", "c1内容");
        Thread.sleep(1000);
 
        zkc.createPersistent("/super" + "/" + "c2", "c2内容");
        Thread.sleep(1000);     
 
        zkc.delete("/super/c2");
        Thread.sleep(1000); 
 
        zkc.deleteRecursive("/super");
        Thread.sleep(Integer.MAX_VALUE);
 
    }
}
(3)订阅zk状态变化
public class ZkStateWatcher {
    
    
    static final String CONNECT_ADDR = "172.21.121.53:2181,172.21.121.54:2181,172.21.121.55:2181";
    static final int CONNECTION_OUTTIME = 5000;
    public static void main(String[] args) throws InterruptedException{
    
    
        ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR),CONNECTION_OUTTIME);
        zkc.subscribeStateChanges(new IZkStateListener() {
    
    
            
            @Override
            public void handleStateChanged(KeeperState state) throws Exception {
    
    
                if(state==KeeperState.SyncConnected){
    
    
                    //当我重新启动后start,监听触发
                    System.out.println("连接成功");
                }else if(state==KeeperState.Disconnected){
    
    
                    System.out.println("连接断开");//当我在服务端将zk服务stop时,监听触发
                }else
                    System.out.println("其他状态"+state);
                
            }
            
            @Override
            public void handleNewSession() throws Exception {
    
    
                System.out.println("---->重建session");
            }
        });
//        zkc.close();
        
        Thread.sleep(Integer.MAX_VALUE);
    }
        
}

2、curator

解决Watch注册一次就会失效的问题

支持直接创建多级结点

提供的 API 更加简单易用

提供更多解决方案并且实现简单,例如:分布式锁

提供常用的ZooKeeper工具类

编程风格更舒服

【1】依赖

 <dependencies>
        <!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
            <type>pom</type>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.2.0</version>
        </dependency>
     	<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.2.0</version>
        </dependency>
    </dependencies>

【2】增删改查

创建连接

 private static void createZkCuratorConnection(String ipPort) {
    
    
        curatorFramework=CuratorFrameworkFactory
                        .builder() // 使用工厂类来建造客户端的实例对象
                        .connectString(ipPort) // 配置zk服务器IP port
                        .sessionTimeoutMs(4000)// 设定会话时间
                        .retryPolicy(new ExponentialBackoffRetry(1000,3))//设置及重连策略
                        .namespace("curator")//方便管理的命名空间,其实就是一级目录
                        .build();//建立管道
        curatorFramework.start();//开启curator

    }

连接关闭

  private static void closeZkCuratorConnection() {
    
    
     curatorFramework.close();
    }

创建节点

    private static void createZnode(String path, String value) throws Exception {
    
    
        curatorFramework
                .create()//创建Znode
                .creatingParentsIfNeeded()//如果是多级结点,这里声明如果需要,自动创建父节点
                .withMode(CreateMode.PERSISTENT)//声明结点类型
                .forPath(path,value.getBytes());//声明结点路径和值
    }

删除节点

private static void deleteZnode(String path) throws Exception {
    
    
        curatorFramework
        .delete()
        .deletingChildrenIfNeeded()//如果有子节点,会先自动删除子节点再删除本结点
        .forPath(path);
    }

查询节点值

    private static void getZnodeData(String path) throws Exception {
    
    
        byte[] dataBytes = curatorFramework.getData().forPath(path);
            System.out.println("结点值为:" +new String(dataBytes));
    }

设置新值

 private static void setValue(String path,String value) throws Exception {
    
    
        Stat stat = curatorFramework.checkExists().forPath(path);
            if (stat==null){
    
    
                System.out.println("Znode does not exists");
            }else {
    
    
                curatorFramework
                        .setData()
                        .withVersion(stat.getVersion())
                        .forPath(path,value.getBytes());
            }
    }

【3】注册节点监听器

Cutator提供了三种完善而又灵活的监听机制

  • PathchildCache ~监听一个节点下子节点的创建、删除、更新
  • NodeCache ~监听一个节点的更新和创建事件(不包括删除)
  • TreeCache ~综合PatchChildCache和INodeCache的特性
(1)添加事件监听
  private static void addWatcherWithNodeCache(String path) throws Exception {
    
    
        final NodeCache nodeCache=new NodeCache(curatorFramework,path,false);
        NodeCacheListener nodeCacheListener=new NodeCacheListener() {
    
    
            @Override
            public void nodeChanged() throws Exception {
    
    
                System.out.println("事件路径:"+nodeCache.getCurrentData().getPath()+"发生数据变化,新数据为"+new String(nodeCache.getCurrentData().getData()));
            }
        };
        nodeCache.getListenable().addListener(nodeCacheListener);
        nodeCache.start();
    }
(2)监听孩子节点变化
 private static void addWatcherWithChildrenCache(String path) throws Exception {
    
    
        final PathChildrenCache childrenCache=new PathChildrenCache(curatorFramework,path,true);//缓存数据
        PathChildrenCacheListener pathChildrenCacheListener=new PathChildrenCacheListener() {
    
    
            @Override
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
    
    
                System.out.println("事件路径:"+pathChildrenCacheEvent.getData().getPath()+"事件类型"+pathChildrenCacheEvent.getType());
            }
        };
        childrenCache.getListenable().addListener(pathChildrenCacheListener);
        childrenCache.start(PathChildrenCache.StartMode.NORMAL);
    }
(3)treeNode监听所有变化
    private static void addWatcherWithTreeCache(String path) throws Exception {
    
    
        TreeCache treeCache=new TreeCache(curatorFramework,path);
        TreeCacheListener treeCacheListener=new TreeCacheListener() {
    
    
            @Override
            public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
    
    
                System.out.println("事件路径:"+treeCacheEvent.getData().getPath()+"事件类型"+treeCacheEvent.getType()+"结点值为"+new String(treeCacheEvent.getData().getData()));

            }
        };
        treeCache.getListenable().addListener(treeCacheListener);
        treeCache.start();
    }
       childrenCache.getListenable().addListener(pathChildrenCacheListener);
        childrenCache.start(PathChildrenCache.StartMode.NORMAL);
    }

猜你喜欢

转载自blog.csdn.net/khuangliang/article/details/107239748