zookeeper

zookeeper

数据存储形式

zookeeper中对用户的数据采用kv形式存储,只是zk有点特别:
key:是以路径的形式表示的,那就以为着,各key之间有父子关系,比如 / 是顶层key,用户建的key只能在/ 下作为子节点,比如建一个key: /aa 这个key可以带value数据,也可以建一个key: /bb,也可以建key: /aa/xx,zookeeper中,对每一个数据key,称作一个znode

znode类型

zookeeper中的znode有多种类型
1、PERSISTENT 持久的:客户端一旦建立,zk会持久保存,除非有客户端手动删除
2、EPHEMERAL 短暂的:创建这个节点的客户端一旦断开与zookeeper集群的联系,zookeeper集群就会自动将该节点删除
3、SEQUENTIAL 带序号的:在同一个父节点下,建带序号的子节点,zk会自动给客户端指定的子节点名后拼接一个自增的序号

组合类型
PERSISTENT :持久不带序号
EPHEMERAL :短暂不带序号
PERSISTENT 且 SEQUENTIAL :持久且带序号
EPHEMERAL 且 SEQUENTIAL :短暂且带序号

zookeeper的集群部署

1、上传安装包到集群服务器
2、解压
3、修改配置文件
进入zookeeper的安装目录的conf目录
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg

# The number of milliseconds of each tick
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/root/zkdata	##修改
clientPort=2181
#autopurge.purgeInterval=1
server.1=n1:2888:3888
server.2=n2:2888:3888
server.3=n3:2888:3888

对3台节点,都创建目录 mkdir /root/zkdata
对3台节点,在工作目录中生成myid文件,但内容要分别为各自的id: 1,2,3
n1上: echo 1 > /data/zkdata/myid
n2上: echo 2 > /data/zkdata/myid
n3上: echo 3 > /data/zkdata/myid

4、从hdp20-01上scp安装目录到其他两个节点
scp -r zookeeper-3.4.6/ n2 P W D s c p − r z o o k e e p e r − 3.4.6 / n 3 : PWD scp -r zookeeper-3.4.6/ n3: PWDscprzookeeper3.4.6/n3:PWD

5、启动zookeeper集群
zookeeper没有提供自动批量启动脚本,需要手动一台一台地起zookeeper进程
在每一台节点上,运行命令:
bin/zkServer.sh start
启动后,用jps应该能看到一个进程:QuorumPeerMain
但是,光有进程不代表zk已经正常服务,需要用命令检查状态:
bin/zkServer.sh status
能看到角色模式:为leader或follower,即正常了。

6.编写集群启动
zkServer_all.sh

#!/bin/bash
for host in n1 n2 n3
do
echo "${host}:${1}ing..."
ssh $host "source /etc/profile;/appdata/zookeeper/bin/zkServer.sh $1"
done

启动:./zkServer_all.sh start
查看状态:./zkServer_all.sh status
关闭:./zkServer_all.sh stop

zookeeper的命令行客户端操作

开启命令行客户端:bin/zkCli.sh
注意:在安装有zookeeper的节点都能执行该命令。

zookeeper的数据存储形式:

1、zookeeper中存储数据的基本形式为: key , value
2、zookeeper中的key是用路径表示的:
/aa : 88888
/aa/bb : “xxoo”
/aa/cc : “edu360”
/tt: 9898
每一个key-value称为一个znode(zookeeper数据节点)

数据管理功能:

创建节点: create /aaa ‘ppppp’
查看节点下的子节点: ls /aaa
获取节点的value: get /aaa
修改节点的value: set /aaa ‘mmmmm’
删除节点:rmr /aaa

数据监听功能:

ls /aaa watch
查看/aaa的子节点的同时,注册了一个监听“节点的子节点变化事件”的监听器
在n1机器上:创建/aaa并监听
在这里插入图片描述
在n2机器上:创建/aaa/bbb,n1出现变化
在这里插入图片描述
get /aaa watch
获取/aaa的value的同时,注册了一个监听“节点value变化事件”的监听器
注意:注册的监听器在正常收到一次所监听的事件后,就失效
在n1进行注册
在这里插入图片描述
在n2进行更改数据
在这里插入图片描述

zookeeper在windows客户端访问

守护线程使用实例

守护线程的特点:主线程运行完毕,守护线程就会自动死亡。

package com.initialize.thread;


public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {

        System.out.println("主线程开始执行......");

        System.out.println("主线程准备启动一个子线程。。。。。");
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("子线程开始执行......");
                while(true){
                    try{
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("子线程打印......");
                }
            }
        });


        //setDaemon(true); 这个子线程就变成了守护线程
        thread.setDaemon(true);
        thread.start();

        System.out.println("主线程启动子线程后的语句......");

        Thread.sleep(10000);
    }

}

Windows客户端访问zookeeper

package com.initialize.demo;


import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.List;

/**
 * zookeeper在Windows客户端的演示
 */
public class ZookeeperClientDemo {

    ZooKeeper zk = null;

    @Before
    public void init() throws IOException {
        //构造一个连接zookeeper的客户端对象
        zk = new ZooKeeper("n1:2181,n2:2181,n3:2181", 2000, null);
    }

    @Test
    public void testCreate() throws KeeperException, InterruptedException {

        //参数1:要创建的节点路径  参数2:数据  参数3:访问权限 参数4:节点类型
        String create = zk.create("/idea", "hello idea".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

        System.out.println(create);

        zk.close();
    }

    @Test
    public void testUpdate() throws KeeperException, InterruptedException {

        //参数1:节点路径  参数2:数据  参数3:所要修改的版本,-1代表任何版本
        zk.setData("/idea", "我爱你".getBytes(), -1);

        zk.close();
    }

    @Test
    public void testGet() throws Exception{

        //参数1:节点路径   参数2:是否要监听  参数3:要获取数据的版本,null代表最新版本
        byte[] data = zk.getData("/idea", false, null);

        System.out.println(new String(data, "UTF-8"));

        zk.close();
    }

    @Test
    public void testListChildren() throws KeeperException, InterruptedException {

        //参数1:节点路径   参数2:是否要监听
        //注意:返回的结果中只有子节点名字,不带全路径
        List<String> children = zk.getChildren("/aaa", false);

        for(String child : children){
            System.out.println(child);
        }
        zk.close();
    }
    
}

Windows客户端监控器

package com.initialize.demo;


import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Before;
import org.junit.Test;


import java.util.List;

public class ZookeeperWatchDemo {

    ZooKeeper zk = null;

    @Before
    public void init() throws Exception {
        //构造一个连接zookeeper的客户端对象
        //参数1:zookeeper服务的主机端口号 参数2:最大超时时间 参数3:注册监听
        zk = new ZooKeeper("n1:2181,n2:2181,n3:2181", 2000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {

                if(event.getState() == Event.KeeperState.SyncConnected && event.getType()== Event.EventType.NodeDataChanged){
                    System.out.println(event.getPath());//收到的事件所发生的节点路径
                    System.out.println(event.getType());//收到的事件类型
                    System.out.println("赶紧换照片,换浴室里面的洗浴套装。。。。");
                    try{
                        zk.getData("/mygirls", true, null);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (KeeperException e) {
                        e.printStackTrace();
                    }
                }else if(event.getState() == Event.KeeperState.SyncConnected && event.getType() == Event.EventType.NodeChildrenChanged){
                    System.out.println("子节点变化了。。。。");
                }

            }
        });
    }

    @Test
    public void testGetWatch() throws  Exception{

        byte[] data = zk.getData("/mygirls", true, null);//监听节点数据变化

        List<String> children = zk.getChildren("/mygirls", true);//监听节点的子节点变化事件

        System.out.println(new String(data, "UTF-8"));

        Thread.sleep(Long.MAX_VALUE);
    }

}

zookeeper图形化客户端插件

在Eclipse环境下安装ZooKeeper状态查看相关的插件步骤如下:

Step 1. 在 Eclipse 菜单打开Help -> Install New Software…
Step 2. 添加 url http://www.massedynamic.org/eclipse/updates/
Step 3. 选择插件并安装运行
Step 4. 在 Eclipse 菜单打开Window->Show View->Other…->ZooKeeper 3.2.2。
Step 5. 连接ZK 输入正在运行的ZK server 地址和端口

zookeeper选举机制示意图

在这里插入图片描述

zookeeper应用案例–分布式系统服务器上下线感知

​​在这里插入图片描述
服务器端源码:

package com.initialize.distributesystem;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

public class TimeQueryService extends Thread{

    int port = 0;
    public TimeQueryService(int port){
        this.port = port;
    }

    @Override
    public void run() {
        try{
            ServerSocket ss = new ServerSocket(port);
            System.out.println("业务线程已绑定端口" + port + "准备接收消费端请求了...");
            while(true){
                Socket sc = ss.accept();
                //阻塞方法,当接收到输入信息时,为inputStream赋值,向下执行。
                InputStream inputStream = sc.getInputStream();
                OutputStream outputStream = sc.getOutputStream();
                outputStream.write(new Date().toString().getBytes());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package com.initialize.distributesystem;


import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

public class TimeQueryServer {

    ZooKeeper zk = null;

    //构造zk客户端连接
    public void connectZK() throws Exception{
        zk = new ZooKeeper("n1:2181,n2:2181,n3:2181", 2000, null);
    }

    //注册服务器信息
    public void registerServerInfo(String hostname, String port) throws Exception{

        /**
         * 先判断注册节点的父节点是否存在,如果不存在,则创建
         *
         */
        Stat stat = zk.exists("/servers", false);
        if(stat == null){
            zk.create("/servers", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }

        //注册服务器数据到zk的约定注册节点下
        String create = zk.create("/servers/server", (hostname+":"+port).getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);

        System.out.println(hostname + "服务器向zk注册信息成功!注册节点为:"+create);
    }

    public static void main(String[] args) throws Exception {

        TimeQueryServer timeQueryServer = new TimeQueryServer();

        //构造zk客户端连接
        timeQueryServer.connectZK();

        //注册服务器信息
        timeQueryServer.registerServerInfo(args[0], args[1]);

        //启动业务线程开始处理业务
        new TimeQueryService(Integer.parseInt(args[1])).start();
    }
}

客户端源码:

package com.initialize.distributesystem;


import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Consumer {

    //定义一个list用于存放最新的在线服务器列表
    private volatile ArrayList<String> onlineServers = new ArrayList<>();

    //构造zk连接对象
    ZooKeeper zk = null;

    //构造zk客户端连接
    public void connectZK() throws IOException {
        zk = new ZooKeeper("n1:2181,n2:2181,n3:2181", 2000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                if(event.getState()== Event.KeeperState.SyncConnected &&event.getType()== Event.EventType.NodeChildrenChanged){

                    try{
                        //事件回调逻辑中,再次查询zk上的在线服务器节点即可,查询逻辑中再次注入了子节点变化的事件监听
                        getOnlineServers();

                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    //查询在线服务器列表
    public void getOnlineServers() throws Exception{
        List<String> children = zk.getChildren("/servers", true);
        ArrayList<String> servers = new ArrayList<>();

        for(String child : children){
            byte[] data = zk.getData("/servers/"+child, false, null);
            String serverInfo = new String(data);
            servers.add(serverInfo);
        }
        onlineServers = servers;
        System.out.println("查询了一次zk,当前在线的服务器有:" + servers);
    }

    public void sendRequest() throws  Exception{
        Random random = new Random();
        while(true){
            try{
                //挑选一台当前在线的服务器
                int nextInt = random.nextInt(onlineServers.size());
                String server = onlineServers.get(nextInt);
                String hostname = server.split(":")[0];
                int port = Integer.parseInt(server.split(":")[1]);
                
                System.out.println("本次请求挑选的服务器为:" + server);

                Socket socket = new Socket(hostname, port);
                OutputStream out = socket.getOutputStream();
                InputStream in = socket.getInputStream();
                
                out.write("haha".getBytes());
                out.flush();
                
                byte[] buf = new byte[256];
                int read = in.read(buf);
                System.out.println("服务器响应的时间为:" + new String(buf, 0, read));

                out.close();
                in.close();
                socket.close();

                Thread.sleep(2000);
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Consumer consumer = new Consumer();

        //构造zk连接对象
        consumer.connectZK();

        //查询在线服务器列表
        consumer.getOnlineServers();

        //处理业务(向一台服务器发送时间查询请求)
        consumer.sendRequest();
    }
}

将程序打成jar包,放到不同的Liunx机器上面运行,分别启动server服务和consumer客户端。观察运行结果。

应用实例示意图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值