zk理论知识点

一、特性

1、高效

适用于大型的分布式系统. 如果写多的话性能不高,因为它要做所有节点之间的数据同步。

2、可靠

支持集群,大部分可用即服务可用

3、顺序

所有写请求由leader生成递增zxid,写操作时,采用mvcc乐观锁机制进行写,保证所有写操作顺序。

4、简洁

对外提供的api非常实用、简洁。仅仅7个api

create - 在树形结构的位置中创建节点

delete - 删除一个节点

exists - 测试节点在指定位置上是否存在

get data - 从节点上读取数据

set data - 往节点写入输入

get chilren - 检索一个节点的子节点列表

sync - 等待传输数据

二、数据模型

1.临时节点

2.临时顺序节点

3.持久节点

4.持久顺序节点

三、zk事件通知

Zookeeper Watcher事件通知 当节点发生变化的时候 修改、删除、新增 都会监听到通知

    ZkClient zkClient = new ZkClient(ADDRES, TIMEOUT);
    String path = "/mayikt-service";

    zkClient.subscribeChildChanges(path, new IZkChildListener() {
        @Override
        public void handleChildChange(String s, List<String> list) throws Exception {
            System.out.println(s + "节点发生了变化,剩余一下节点");
            list.forEach((t) -> System.out.println(t));
        }
    });

    zkClient.subscribeDataChanges(path+"/8080", new IZkDataListener() {
        @Override
        public void handleDataChange(String s, Object o) throws Exception {
            System.out.println(s + "节点内容发生了变化:" + o);
        }

        @Override
        public void handleDataDeleted(String s) throws Exception {
            System.out.println(s + "节点被移除~~~");
        }
    });

四、zk实现分布式锁的原因

因为Zookeeper节点路径保持唯一,不允许重复 且有临时节点特性连接关闭后当前节点会自动消失,从而实现分布式锁。

实现原理:

1.多请求同时创建相同的节点(lockPath),只要谁能够创建成功 谁就能够获取到锁;

2.如果创建节点的时候,突然该节点已经被其他请求创建的话则直接等待;

3.只要能够创建节点成功,则开始进入到正常业务逻辑操作,其他没有获取锁进行等待;

4.正常业务逻辑流程执行完后,调用zk关闭连接方式释放锁,从而是其他的请求开始进入到获取锁的资源。

如果使用zk实现分布式锁,获取锁之后业务逻辑方法一直没有执行完毕,导致其他所有的请求等待的话如何解决?

设置Session连接超时时间,在规定的时间内获取锁后超时啦~自动回滚当前数据库业务逻辑。

public class OrderNumGenerator {
    // 全局id
    private static int count = 0;

    public String getNumber() {
        SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        try {
            Thread.sleep(30);
        } catch (Exception e) {

        }
        return simpt.format(new Date()) + "-" + ++count;
    }
}
public interface Lock {
    /**
     * 获取锁
     */
    void getLock();

    /**
     * 释放锁
     */
    void unLock();
}
public abstract class ZookeeperAbstractTemplateLock implements Lock {
    //参数1 连接地址
    private static final String ADDRES = "192.168.212.147:2181";
    // 参数2 zk超时时间
    private static final int TIMEOUT = 5000;
    // 计数器
    protected static CountDownLatch countDownLatch = null;
    // 创建zkClient连接
    protected ZkClient zkClient = new ZkClient(ADDRES, TIMEOUT);
    protected String lockPaht = "/lockPath";

    @Override
    public void getLock() {
        if (tryLock()) {
            System.out.println(Thread.currentThread().getName() + ">>>获取锁信息成功<<<<");
        } else {
            // 等待
            waitLock();
            //重新获取锁
            getLock();
        }
    }

    // 尝试获取锁
    protected abstract boolean tryLock();

    // 当前线程等待
    protected abstract boolean waitLock();

    @Override
    public void unLock() {
        if (zkClient != null) {
            System.out.println(Thread.currentThread().getName() + ">>>关闭锁成功<<<<");
            zkClient.close();
        }
    }
}
public class ZookeeperTemplateImplLock extends ZookeeperAbstractTemplateLock {
    @Override
    protected boolean tryLock() {
        try {
            String s = zkClient.create(lockPaht, lockPaht, CreateMode.EPHEMERAL);
            // 获取锁成功
            return true;
        } catch (Exception e) {
//            // 获取锁失败
//            e.printStackTrace();
            return false;
        }
    }

    @Override
    protected boolean waitLock() {
        //采用时间监听节点是否被删除
        IZkDataListener iZkDataListener = new IZkDataListener() {

            @Override
            public void handleDataChange(String s, Object o) throws Exception {

            }

            @Override
            public void handleDataDeleted(String s) throws Exception {
                if (countDownLatch != null) {
                    countDownLatch.countDown();//重新进入获取锁
                }
            }
        };
        // 注册当前监听事件通知
        zkClient.subscribeDataChanges(lockPaht, iZkDataListener);
        // 判断当前节点是否存在,如果存在就等待
        if (zkClient.exists(lockPaht)) {
            if (countDownLatch == null) {
                countDownLatch = new CountDownLatch(1);
            }
            try {
                // 等待
                countDownLatch.await();
            } catch (Exception e) {

            }
            // 正常执行业务逻辑  重新获取锁
        }
        // 移除事件通知
        zkClient.unsubscribeDataChanges(lockPaht, iZkDataListener);
        return false;
    }
}
public class OrderService implements Runnable {
    // 生产订单号码
    private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
    //    private Lock lock = new ReentrantLock();
    private Lock lock = new ZookeeperTemplateImplLock();

    @Override
    public void run() {
        getNumber();

    }

    private void getNumber() {
        try {
            lock.getLock();
            String number = orderNumGenerator.getNumber();
            System.out.println("number:" + number);
        } catch (Exception e) {

        } finally {
            lock.unLock();
        }
    }
}

 

 

一、特性1、高效适用于大型的分布式系统. 如果写多的话性能不高,因为它要做所有节点之间的数据同步。2、可靠支持集群,大部分可用即服务可用3、顺序所有写请求由leader生成递增zxid,写操作时,采用mvcc乐观锁机制进行写,保证所有写操作顺序。4、简洁对外提供的api非常实用、简洁。仅仅7个apicreate - 在树形结构的位置中创建节点delete - 删除一个节点exists - 测试节点在指定位置上是否存在get data - 从节点上读取数据set data - 往节点写入输入get chilren - 检索一个节点的子节点列表sync - 等待传输数据二、数据模型1.临时节点2.临时顺序节点3.持久节点4.持久顺序节点三、zk事件通知Zookeeper Watcher事件通知 当节点发生变化的时候 修改、删除、新增 都会监听到通知ZkClient zkClient = new ZkClient(ADDRES, TIMEOUT);String path = "/mayikt-service";
zkClient.subscribeChildChanges(path, new IZkChildListener() {@Overridepublic void handleChildChange(String s, List<String> list) throws Exception {System.out.println(s + "节点发生了变化,剩余一下节点");list.forEach((t) -> System.out.println(t));}});
zkClient.subscribeDataChanges(path+"/8080", new IZkDataListener() {@Overridepublic void handleDataChange(String s, Object o) throws Exception {System.out.println(s + "节点内容发生了变化:" + o);}
@Overridepublic void handleDataDeleted(String s) throws Exception {System.out.println(s + "节点被移除~~~");}});四、zk实现分布式锁的原因因为Zookeeper节点路径保持唯一,不允许重复 且有临时节点特性连接关闭后当前节点会自动消失,从而实现分布式锁。实现原理:1.多请求同时创建相同的节点(lockPath),只要谁能够创建成功 谁就能够获取到锁;2.如果创建节点的时候,突然该节点已经被其他请求创建的话则直接等待;3.只要能够创建节点成功,则开始进入到正常业务逻辑操作,其他没有获取锁进行等待;4.正常业务逻辑流程执行完后,调用zk关闭连接方式释放锁,从而是其他的请求开始进入到获取锁的资源。如果使用zk实现分布式锁,获取锁之后业务逻辑方法一直没有执行完毕,导致其他所有的请求等待的话如何解决?设置Session连接超时时间,在规定的时间内获取锁后超时啦~自动回滚当前数据库业务逻辑。
public class OrderNumGenerator {    // 全局id    private static int count = 0;
    public String getNumber() {        SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");        try {            Thread.sleep(30);        } catch (Exception e) {
        }        return simpt.format(new Date()) + "-" + ++count;    }}



public interface Lock {    /**     * 获取锁     */    void getLock();
    /**     * 释放锁     */    void unLock();}



public abstract class ZookeeperAbstractTemplateLock implements Lock {    //参数1 连接地址    private static final String ADDRES = "192.168.212.147:2181";    // 参数2 zk超时时间    private static final int TIMEOUT = 5000;    // 计数器    protected static CountDownLatch countDownLatch = null;    // 创建zkClient连接    protected ZkClient zkClient = new ZkClient(ADDRES, TIMEOUT);    protected String lockPaht = "/lockPath";
    @Override    public void getLock() {        if (tryLock()) {            System.out.println(Thread.currentThread().getName() + ">>>获取锁信息成功<<<<");        } else {            // 等待            waitLock();            //重新获取锁            getLock();        }
    }
    // 尝试获取锁    protected abstract boolean tryLock();
    // 当前线程等待    protected abstract boolean waitLock();
    @Override    public void unLock() {        if (zkClient != null) {            System.out.println(Thread.currentThread().getName() + ">>>关闭锁成功<<<<");            zkClient.close();        }    }}

public class ZookeeperTemplateImplLock extends ZookeeperAbstractTemplateLock {    @Override    protected boolean tryLock() {        try {            String s = zkClient.create(lockPaht, lockPaht, CreateMode.EPHEMERAL);            // 获取锁成功            return true;        } catch (Exception e) {//            // 获取锁失败//            e.printStackTrace();            return false;        }    }
    @Override    protected boolean waitLock() {        //采用时间监听节点是否被删除        IZkDataListener iZkDataListener = new IZkDataListener() {
            @Override            public void handleDataChange(String s, Object o) throws Exception {
            }
            @Override            public void handleDataDeleted(String s) throws Exception {                if (countDownLatch != null) {                    countDownLatch.countDown();//重新进入获取锁                }            }        };        // 注册当前监听事件通知        zkClient.subscribeDataChanges(lockPaht, iZkDataListener);        // 判断当前节点是否存在,如果存在就等待        if (zkClient.exists(lockPaht)) {            if (countDownLatch == null) {                countDownLatch = new CountDownLatch(1);            }            try {                // 等待                countDownLatch.await();            } catch (Exception e) {
            }            // 正常执行业务逻辑  重新获取锁        }        // 移除事件通知        zkClient.unsubscribeDataChanges(lockPaht, iZkDataListener);        return false;    }}


public class OrderService implements Runnable {    // 生产订单号码    private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();    //    private Lock lock = new ReentrantLock();    private Lock lock = new ZookeeperTemplateImplLock();
    @Override    public void run() {        getNumber();
    }
    private void getNumber() {        try {            lock.getLock();            String number = orderNumGenerator.getNumber();            System.out.println("number:" + number);        } catch (Exception e) {
        } finally {            lock.unLock();        }    }}

posted on 2020-03-15 18:28  JAVA-ROAD  阅读(318)  评论(0)    收藏  举报

导航