一、zookeeper从入门到精通、基础原理及API使用介绍

版权声明:如需转载,请标明转载出处哦! https://blog.csdn.net/Z0157/article/details/82717395

目录

1.1分布式的概念和基础

一、zookeeper不适用的场景:

二、zookeeper面临了很多分布式系统带来的问题。

1.2、zookeeper架构

1.3、java API 的使用(demo):


1.1分布式的概念和基础

一、zookeeper不适用的场景:

整个ZooKeeper的服务器集群管理着应用协作的关键数据。

ZooKeeper不适合用作海量数据存储。对于需要存储海量的应用数据的情况,我们有很多备选方案,比如说数据库和分布式文件系统等。因为不同的应用有不同的需求,如对一致性和持久性的不同需求,所以在设计应用时,最佳实践还是应该将应用数据和协同数据独立开。

二、zookeeper面临了很多分布式系统带来的问题。

(1)、分布式系统中的进程通信有两种选择:直接通过网络进行信息交换,或读写某些共享存储。ZooKeeper使用共享存储模型来实现应用间的协作和同步原语。对于共享存储本身,又需要在进程和存储间进行网络通信。网络通信是分布式系统中并发设计的基础。

(2)、面临的网络消息延迟、处理器的性能、单个节点处理器的时钟偏移问题。

(3)、主从模式的系统要解决一下三个关键问题:

  • 主节点崩溃:如果主节点发送错误并失效,系统将无法分配新的任务或重新分配已失败的任务。
  •  从节点崩溃:如果从节点崩溃,已分配的任务将无法完成。
  • 通信故障:如果主节点和从节点之间无法进行信息交换,从节点将无法得知新任务分配给它。也有     可能会把同一个任务分配到不同的节点重复执行。

(4)、对上面的问题,我们自然会有以下下需求:

        (a)、主节点选举:这是关键的一步,使得主节点可以给从节点分配任务。

        (b)、崩溃检测:主节点必须具有检测从节点崩溃或失去连接的能力。

        (c)、组成员关系管理:主节点必须具有知道哪一个从节点可以执行任务的能力。

        (d)、元数据管理:主节点和从节点必须具有通过某种可靠的方式来保存分配状态和执行状态的能力。

1.2、zookeeper架构

1、ZooKeeper操作和维护一个小型的数据节点,这些节点被称为znode,采用类似于文件系统的层级树状结构进行管理。下图描述了一个znode树的结构,根节点包含4个子节点,其中三个子节点拥有下一级节点,叶子节点存储了数据信息。

ZooKeeper数据树结构示例

/workers节点作为父节点,其下每个znode子节点保存了系统中一个可用从节点信息。如图所示,有一个从节点(foot.com:2181)。

/tasks节点作为父节点,其下每个znode子节点保存了所有已经创建并等待从节点执行的任务的信息,主-从模式的应用的客户端在/tasks下添加一个znode子节点,用来表示一个新任务,并等待任务状态的znode节点。

/assign节点作为父节点,其下每个znode子节点保存了分配到某个从节点的一个任务信息,当主节点为某个从节点分配了一个任务,就会在/assign下增加一个子节点。

2、znode一共有4种类型:持久的(persistent)、临时的(ephemeral)、持久有序的(persistent_sequential)和临时有序的。

(1)、持久节点:

znode节点可以是持久(persistent)节点,还可以是临时(ephemeral)节点。持久化的znode,如/path,只能通过调用delete来进行删除。

(2)、持久化有序节点:

 每个节点都会为它的一级子节点维护一个顺序

(3)、临时节点

当创建该节点的客户端崩溃或关闭了与ZooKeeper的连接时,这个节点就会被删除。

一个临时znode,在以下两种情况下将会被删除:

a、当创建该znode的客户端的会话因超时或主动关闭而中止时。

b、当某个客户端(不一定是创建者)主动删除该节点时。

因为临时的znode在其创建者的会话过期时被删除,所以我们现在不允许临时节点拥有 子节点。

a、临时有序节点:在临时节点上多一个顺序性特性。

b、zookeeper API (zookeeper的命令操作)

(1)、create [-s] [-e] path data acl

-s 表示节点是否有序

-e 表示是否为临时节点

默认情况下,是持久化节点

(2)、 get path [watch]

获得指定 path的信息

(3)、set path data [version]

修改节点 path对应的data

乐观锁的概念

数据库里面有一个 version 字段去控制数据行的版本号

(4)、delete path [version]

删除节点

stat信息

cversion = 0       子节点的版本号

aclVersion = 0     表示acl的版本号,修改节点权限

dataVersion = 1    表示的是当前节点数据的版本号

czxid    节点被创建时的事务ID

mzxid   节点最后一次被更新的事务ID

pzxid    当前节点下的子节点最后一次被修改时的事务ID

ctime = Sat Aug 05 20:48:26 CST 2017

mtime = Sat Aug 05 20:48:50 CST 2017

cZxid = 0x500000015

ctime = Sat Aug 05 20:48:26 CST 2017

mZxid = 0x500000016

mtime = Sat Aug 05 20:48:50 CST 2017

pZxid = 0x500000015

cversion = 0

dataVersion = 1

aclVersion = 0

ephemeralOwner = 0x0   创建临时节点的时候,会有一个sessionId 。 该值存 储的就是这个sessionid

dataLength = 3    数据值长度

numChildren = 0  子节点数.

1.3、java API 的使用(demo):

package com.zhurong.zk.api;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

/**
 * Description:
 * User: zhurong
 * Date: 2018-09-09  11:56
 */
public class CreateSessionDemo {

    /*server.1=192.168.1.103:2888:3888
    server.2=192.168.1.104:2888:3888
    server.3=192.168.1.105:2888:3888*/
    public final static String CONNECTSTRING="192.168.1.103:2181,192.168.1.104:2181,192.168.1.105:2181";
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    public static Stat stat = new Stat();
    static ZooKeeper zooKeeper;
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        zooKeeper = new ZooKeeper(CONNECTSTRING, 5000, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                System.out.println("111:"+watchedEvent.getState());
                if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
                    countDownLatch.countDown();
                    System.out.println("222:"+watchedEvent.getState());
                }
            }
        });
        countDownLatch.await();
        System.out.println("333:"+zooKeeper.getState());
    }
}

package com.zhurong.zk.api;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Description:
 * User: zhurong
 * Date: 2018-09-09  11:56
 */
public class CreateNodeDemo implements Watcher {

    /*server.1=192.168.1.103:2888:3888
    server.2=192.168.1.104:2888:3888
    server.3=192.168.1.105:2888:3888*/
    public final static String CONNECTSTRING = "192.168.1.103:2181,192.168.1.104:2181,192.168.1.105:2181";
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    public static Stat stat = new Stat();
    static ZooKeeper zooKeeper;

    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        zooKeeper = new ZooKeeper(CONNECTSTRING, 5000, new CreateNodeDemo());
        countDownLatch.await();
        System.out.println("333:" + zooKeeper.getState());
        /**
         ZooDefs.Ids.OPEN_ACL_UNSAFE:节点权限,任何人有权限
         [
         任何id可以访问,创建者可以访问,可读权限,授权id节点
         ]
         CreateMode.EPHEMERAL:临时节点
         * */
        String result = zooKeeper.create("/node1", "this node123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL);
        zooKeeper.getData("/node1", true, stat);
        System.out.println("创建节点成功:" + result);

        zooKeeper.setData("/node1", "set data".getBytes(), -1);
        zooKeeper.setData("/node1", "set data2".getBytes(), -1);
        Thread.sleep(1000);
        //删除节点
        zooKeeper.delete("/node1",-1);

        //创建节点和子节点
        String path="/node11";

        zooKeeper.create(path,"123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
        TimeUnit.SECONDS.sleep(1);

        Stat stat=zooKeeper.exists(path+"/node1",true);
        if(stat==null){//表示节点不存在
            zooKeeper.create(path+"/node1","123".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
            TimeUnit.SECONDS.sleep(1);
        }
        //修改子路径
        zooKeeper.setData(path+"/node1","mic123".getBytes(),-1);
        TimeUnit.SECONDS.sleep(1);


        //获取指定节点下的子节点
        List<String> childrens=zooKeeper.getChildren("/node1",true);
        System.out.println(childrens);

        Thread.sleep(3000);
    }


    public void process(WatchedEvent watchedEvent) {
        try {
            System.out.println("111:" + watchedEvent.getState());
            if (watchedEvent.getState() == Watcher.Event.KeeperState.SyncConnected) {
                System.out.println("watchEvent:" + watchedEvent.getType());
                if (Event.EventType.None == watchedEvent.getType() && watchedEvent.getPath() == null) {
                    countDownLatch.countDown();
                } else if (watchedEvent.getType() == Watcher.Event.EventType.NodeDataChanged) {
                    System.out.println("notedatachanged");
                    System.out.println("path:" + watchedEvent.getPath() + "改变后的node值:" +
                            zooKeeper.getData(watchedEvent.getPath(), false, stat));//true:继续去注册一个监听的时间
                } else if (watchedEvent.getType() == Watcher.Event.EventType.NodeChildrenChanged) {
                    System.out.println("子节点数据变更路径:"+watchedEvent.getPath()+"->节点的值:"+
                            zooKeeper.getData(watchedEvent.getPath(),true,stat));
                } else if (watchedEvent.getType() == Watcher.Event.EventType.NodeCreated) {
                    System.out.println("path:" + watchedEvent.getPath() + "创建的node值:" +
                            zooKeeper.getData(watchedEvent.getPath(), true, stat));//true:继续去注册一个监听的时间
                } else if (watchedEvent.getType() == Watcher.Event.EventType.NodeDeleted) {
                    System.out.println("path:" + watchedEvent.getPath() + "删除的node值:" +
                            zooKeeper.getData(watchedEvent.getPath(), true, stat));//true:继续去注册一个监听的时间
                } else if (watchedEvent.getType() == Event.EventType.NodeChildrenChanged) {
                    System.out.println("path:" + watchedEvent.getPath() + "子节点的node值:" +
                            zooKeeper.getData(watchedEvent.getPath(), true, stat));//true:继续去注册一个监听的时间
                }
            }
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Z0157/article/details/82717395