一、vmware设置虚拟机centeros的ip

1、设置vm属性

先设置NAT模式

Zookeeper 支持ipv6 zookeeper设置ip_Zookeeper 支持ipv6

点击菜单栏编辑

Zookeeper 支持ipv6 zookeeper设置ip_zookeeper_02

记录子网网关地址

Zookeeper 支持ipv6 zookeeper设置ip_zookeeper_03

Zookeeper 支持ipv6 zookeeper设置ip_System_04

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、更改本地配置

Zookeeper 支持ipv6 zookeeper设置ip_zookeeper_05

Zookeeper 支持ipv6 zookeeper设置ip_zookeeper_06

4、验证

通过xshell ping下linuxip

Zookeeper 支持ipv6 zookeeper设置ip_zookeeper_07

连接成功

Zookeeper 支持ipv6 zookeeper设置ip_apache_08

连接外网成功

Zookeeper 支持ipv6 zookeeper设置ip_apache_09

二、安装zookeeper

1、下载zookeeper

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

Zookeeper 支持ipv6 zookeeper设置ip_zookeeper_10

2、解压到opt目录下

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

Zookeeper 支持ipv6 zookeeper设置ip_zookeeper_11

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

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

4、设置zookeeper的path路径

vi /etc/profile

加入环境变量

export ZK_HOME=/opt/zookeeper

export PATH=Zookeeper 支持ipv6 zookeeper设置ip_Zookeeper 支持ipv6_12PATH

应用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

Zookeeper 支持ipv6 zookeeper设置ip_Zookeeper 支持ipv6_13

6、启动zk

zkServer.sh start

Zookeeper 支持ipv6 zookeeper设置ip_Zookeeper 支持ipv6_14

zkServer.sh status

Zookeeper 支持ipv6 zookeeper设置ip_apache_15

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

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)

Zookeeper 支持ipv6 zookeeper设置ip_System_16

需要关闭防火墙

systemctl stop firewalld

9、启动

命令

zkServer.sh start

zkServer.sh restart

zkServer.sh status

zkServer.sh stop

结果

zkOS1

Zookeeper 支持ipv6 zookeeper设置ip_zookeeper_17

zkOS2

Zookeeper 支持ipv6 zookeeper设置ip_apache_18

zkOS3

Zookeeper 支持ipv6 zookeeper设置ip_Zookeeper 支持ipv6_19

zkOS4

Zookeeper 支持ipv6 zookeeper设置ip_zookeeper_20

三、zk故障恢复

1、正常状态数据

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

2、模拟leader宕机

leader是server2

Zookeeper 支持ipv6 zookeeper设置ip_System_21

zkServer3成为新的leader

重新启动zkSever2成为follower

Zookeeper 支持ipv6 zookeeper设置ip_apache_22

四、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);
    }