1.Zookeeper功能和特性

2.节点类型四种!四种!四种!

3.命令简单介绍

3.1 服务端命令

3.2 客户端命令

4.Curator --Zookeeper的api

4.1 创建连接

4.2 增删改查

4.3 Watch 监听事件

4.4 分布式锁

5.Zookeeper 集群介绍

5.1 leader选举

5.2 伪集群部署经验

5.3 集群发生问题的时候节点变化(集群数量为3台的情况)

5.4 zookeeper中的角色(3种)


1.Zookeeper功能和特性

特点:分布式、开源、树形目录

功能:配置管理、分布式锁、集群管理

这边就不介绍安装,安装很简单没什么特别的步骤,配置一个zoo.cfg

zookeeper 单节点IP zookeeper之节点基本操作二_zookeeper

2.节点类型四种!四种!四种!

命令看不懂看下面基本命令的介绍

节点类型

命令操作

持久节点

create 节点路径

不可以一直执行因为节点路径是唯一的

临时节点

create -e 节点路径

不可以一直执行因为节点路径是唯一的

但是quit之后这个节点就没了

持久话顺序节点

create -s 节点路径

这个命令是可以一直执行的,因为这个节点后面是有数字再自增

临时顺序节点

create -es 节点路径

这个命令是可以一直执行的,因为这个节点后面是有数字再自增

但是quit之后这个节点就没了

3.命令简单介绍

3.1 服务端命令

./zkServer.sh status

查看Zookeeper状态

./zkServer.sh start

开启

./zkServer.sh stop

关闭

./zkServer.sh restart

重启

3.2 客户端命令

./zkCli.sh -server localhost:2181

连接zookeeper服务器

quit

断开服务器

ls

查看某个节点的信息

create 你的节点路径 你的节点值

create 你的节点路径

创建节点注意前面都是有空格的

例如create /yasuo hasai

可以不写值后面再set

get 你的节点路径

获取节点信息

set 你的节点路径

给节点设置值

delete 你的节点路径

删除节点,如果有子节点删不了

deleteall 你的节点路径

如果有子节点,也删除

help

帮助

ls -s 节点路径

可以查看该节点的属性,这个非常关键,后面会用到这些值。

4.Curator --Zookeeper的api

当然还有其他api这边只介绍Curator

4.1 创建连接

private CuratorFramework curatorFramework1;
    
    public void testconConnect(){
        /**
         * Create a new client
         *
         * @param connectString       地址和端口
         * @param sessionTimeoutMs    会话超时
         * @param connectionTimeoutMs 连接超时
         * @param retryPolicy         重试策略
         * @return client
         */
        String connectString="localhost:2181";
        int sessionTimeoutMs = 60*1000;//这个是默认值
        int connectionTimeoutMs = 15*1000;
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10);
        
        //第一种连接方式
//        CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(connectString, sessionTimeoutMs, connectionTimeoutMs, retryPolicy);
//        curatorFramework.start();
        //第二种连接方式
        curatorFramework1 = CuratorFrameworkFactory.builder()
                .connectString(connectString)
                .sessionTimeoutMs(sessionTimeoutMs)
                .sessionTimeoutMs(connectionTimeoutMs)
                .retryPolicy(retryPolicy).namespace("yxlm").build();
//这边的namespace是命名空间,以后操作这个节点下面的子节点不用加这个空间节点
        curatorFramework1.start();
    }

4.2 增删改查

这边比较重要的可以看一下,修改逻辑的version还有删除逻辑的回调的的用法。

//增加节点,注意这边会加上namepace的路径
String yasuo = curatorFramework1.create().forPath("/yasuo");
//增加并设置值
String laoba = curatorFramework1.create().forPath("/laoba","嗨嗨嗨".getBytes());
//这边的withmode 就是-e -s -es 的枚举类型
String laoba2 = curatorFramework1.create().withMode(CreateMode.EPHEMERAL).forPath("/laoba2");
//创建多级节点必须这样搞
String shitouren = curatorFramework1.create().creatingParentsIfNeeded().forPath("/yxlm/shitouren");
//查询节点
byte[] bytes = curatorFramework1.getData().forPath("/yasuo");
//这边查询的是根节点,但是我们前面设置的namespace
List<String> strings = curatorFramework1.getChildren().forPath("/");
//节点状态信息
Stat stat = new Stat();
//创建多级节点
curatorFramework1.getData().storingStatIn(stat).forPath("/app4/zhangxin");
//获取里面的一个属性
System.out.println(stat.getVersion());
//修改数据
curatorFramework1.setData().forPath("/yasuo","哈撒ki".getBytes());
//带着版本改,因为怕多个线程同时改一笔数据,就不好管控
Stat stat = new Stat();
//创建多级节点
curatorFramework1.getData().storingStatIn(stat).forPath("/yasuo");
//withversion会带看现在是第几个版本,改完会自动加一,修改带版本
curatorFramework1.setData().withVersion(6).forPath("/yasuo","哈撒ki1111".getBytes());
System.out.println(stat.getVersion());
//删除的时候,可能会出现删不掉的情况,比如网络问题啊啥的,但是加上guaranteed就一定会删掉
curatorFramework1.delete().guaranteed().forPath("/");
curatorFramework1.delete().guaranteed().inBackground((CuratorFramework client, CuratorEvent event)->{
    System.out.println("被删除了,我需要做点什么");
    //这边可以根据client和event的值进行相关的逻辑操作
}).forPath("/");

4.3 Watch 监听事件

例如发布订阅啥的功能,都是根据这个功能实现的  三种监听的方法

//监听某个节点的变化
public void testNodeCach() throws Exception {
        //监听客户端和路径
        NodeCache nodeCache = new NodeCache(curatorFramework1,"/");
        nodeCache.getListenable().addListener(()->{
            //变化了,监听
            System.out.println("变化了");
            byte[] data = nodeCache.getCurrentData().getData();
            //获取数据
            System.out.println(new String(data));
        });
        //这边开启线程
        nodeCache.start();
        while(true){

        }
    }

 //监听子节点的变化,自身的变化无感知
public void testPathChildrenCache() throws Exception {
//监听客户端和路径
PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework1,"/",true);
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
     System.out.println(pathChildrenCacheEvent);
     //可以根据这个里面的信息进行相关操作
}
});
    //这边开启线程
 pathChildrenCache.start();
        while(true){

        }
    }

//监听自己和子节点
    public void testTreeCache() throws Exception {
        //监听客户端和路径
        TreeCache treeCache = new TreeCache(curatorFramework1,"/");
        treeCache.getListenable().addListener(new TreeCacheListener() {
              @Override
              public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
                  System.out.println(treeCacheEvent);
              }
          }
        );
        //这边开启线程
        treeCache.start();
        while(true){

        }
    }

4.4 分布式锁

概念:跨机器线程之间的数据同步问题

一般做分布式锁有三种,数据库层面,redis,zookeeper。

zookeeper分布式锁原理

zookeeper 单节点IP zookeeper之节点基本操作二_zookeeper_02

 分布式锁案例 --卖票

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.util.concurrent.TimeUnit;

//这边肯定是要加上一个锁对象,
// 这边直接用分布式锁,但是锁对象是现成的
public class SellTicket {
    private static int num = 20;
    private static String connectString="ip:2181";
    private static int sessionTimeoutMs = 60*1000;//这个是默认值
    private static int connectionTimeoutMs = 15*1000;
    private static RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,10);
    private static InterProcessMutex lock = null;
     static {
        CuratorFramework yxlm = CuratorFrameworkFactory.builder()
                .connectString(connectString)
                .sessionTimeoutMs(sessionTimeoutMs)
                .sessionTimeoutMs(connectionTimeoutMs)
                .retryPolicy(retryPolicy).namespace("yxlm").build();
         //这边必须要启动如果不启动,会报错!
         yxlm.start();
         lock= new InterProcessMutex(yxlm,"/yasuo");
    }

    public static void main(String[] args) {
        new Thread(()->{
            while (true){
                try {
                    lock.acquire(3, TimeUnit.SECONDS);
                if(num>0)
                {
                    num--;
                    System.out.println(Thread.currentThread().getName()+num);
                }
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    try {
                        //释放
                        lock.release();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

        }).start();

        new Thread(()->{
            try {
                lock.acquire(30, TimeUnit.SECONDS);
                if(num>0)
                {
                    num--;
                    System.out.println(Thread.currentThread().getName()+num);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                try {
                    //释放
                    lock.release();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

5.Zookeeper 集群介绍

5.1 leader选举

zookeeper 自己有独特的算法,影响的参数呢serviceId和zxid 数值越大,那么成为leader的几率越大。成为leader必须投票,zookeeper启动的时候算法就开始计算,第一台启动投给自己,第二台启动的时候会和一比较然后算出中间较大的,成为leader看总数,如果一台机器超过半数的票,就成为leader后面的机器也不会投票或者成为leader。如果有5台机器,那么获得三票的自动成为leader。

5.2 伪集群部署经验

这边主要就是zoo.cfg 文件的配置里面

// 这边我只是拿出一个zookeeper的zoo.cfg 来举例
//不同zookeeper 不一样的clientPort、dataDir
dataDir=/zookeeper-cluster/zk1/data
clientPort=2182
//下面是一样的每个文件都要配置相同数量的事server.xxxx
//我之前一个文件配置一个疯狂有问题
server.1=localhost:2881:3881
server.2=localhost:2882:3882
server.3=localhost:2883:3883

5.3 集群发生问题的时候节点变化(集群数量为3台的情况)

假设有三台机器,那么就会有一个leader和两个follower机器

如果其中一台follower挂了不影响使用,如果两台follower都挂了,那么剩下的一台将会进入休眠模式。如果其中一个follower启动了将会恢复leader的使用

但是如果leader挂了两台follower会重新选举一个leader,如果一主一从都挂了,那么剩下的那一台也会进入休眠状态

5.4 zookeeper中的角色(3种)

角色名称

角色功能

leader领导者

处理事务请求,然后把更改信息的同步到各个follower和observer的节点上

follower追随者

处理非事务请求,有投票权

observer观察者

处理事务请求,主要是分担追随者的压力