Zookeeper基础+Zookeeper实战分布式锁

Zookeeper基础

一、Zookeeper概述

什么是ZooKeeper

ZooKeeper是一个分布式开源框架,提供了协调分布式应用的基本服务,它向外部应用暴露一组通用服务——分布式同步(Distributed Synchronization)、命名服务(Naming Service)、集群维护(Group Maintenance)等,简化分布式应用协调及其管理的难度,提供高性能的分布式服务。ZooKeeper本身可以以Standalone模式安装运行,不过它的长处在于通过分布式ZooKeeper集群(一个Leader,多个Follower),基于一定的策略来保证ZooKeeper集群的稳定性和可用性,从而实现分布式应用的可靠性。
Zookeeper是一个分布式协调服务,为用户的分布式应用程序提供协调服务
1、zookeeper是为别的分布式程序服务的
2、Zookeeper本身就是一个分布式程序(只要有半数以上节点存活,zk就能正常服务)
3、Zookeeper所提供的服务涵盖:主从协调、服务器节点动态上下线、统一配置管理、分布式共享锁、统> 一名称服务等
4、虽然说可以提供各种服务,但是zookeeper在底层其实只提供了两个功能:
管理(存储,读取)用户程序提交的数据(类似namenode中存放的metadata); 

并为用户程序提供数据节点监听服务;


二、Zookeeper结构



三、Windows环境下搭建Zookeeper 

解压zookeeper-3.4.10.tar.gz ,重命名配置文件zoo_sample.cfg 为 zoo.cfg
解压ZooInspector.zip(zk可视化客户端)

启动zk服务端:zkServer.cmd 
启动zk客户端:zkCli.cmd

查看节点信息:ls /
创建节点信息:create /test 值
创建子节点信息:create /test/001 值
获取节点内容: get /test
修改节点内容: set /test "修该值"
删除节点      : delete /test
退出客户端:quit
 
四、Java语言操作Zookeeper 


 
五、创建Zookeeper临时节点 



六、Watcher事件通知


Zookeeper实战分布式锁 

一、使用Zookeeper实现分布式锁概述 


 
二、解决生产订单号线程安全问题 



三、实现分布式锁解决方案 



四、Zookeeper概述



五、使用Zookeeper实现分布式锁

/**
 * lock锁 自定义分布式锁
 * Created by yz on 2018/4/7.
 */
public interface Lock {

    // 获取锁
    public void getLock();

    // 释放锁
    public void unLock();

}
import org.I0Itec.zkclient.ZkClient;
import java.util.concurrent.CountDownLatch;

/**
 * 重构重复代码,将重复代码交给子类执行
 * Created by yz on 2018/4/7.
 */
public abstract class ZookeeperAbstractLock implements Lock{

    // zk连接地址
    private static final String CONNECTSTRING="127.0.0.1:2181";

    // 创建zk连接
    protected ZkClient zkClient = new ZkClient(CONNECTSTRING);

    protected static final String PATH="/lock";

    protected CountDownLatch countDownLatch = null;

    @Override
    public void getLock() {
        if(tryLock()){
            System.out.println("-----获取锁成功-----");
        }else{
            // 等待
            waitLock();
            // 信号量通知,重新获取锁
            getLock();
        }
    }

    // 等待
    abstract void waitLock();

    // 是否获取锁成功,成功返回true,失败返回false
    abstract Boolean tryLock();

    @Override
    public void unLock() {
        if(zkClient !=null){
            zkClient.close();
            System.out.println("释放锁资源成功");
        }
    }
}
import org.I0Itec.zkclient.IZkDataListener;
import java.util.concurrent.CountDownLatch;

/**
 * Created by yz on 2018/4/7.
 */
public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock{

    @Override
    void waitLock() {
        // 使用zk事件监听,获取到节点被删除
        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){
                    // 唤醒await
                    countDownLatch.countDown();
                }

            }
        };

        //注册节点信息
        zkClient.subscribeDataChanges(PATH,iZkDataListener);
        // 检测节点
        if(zkClient.exists(PATH)){
            // 创建信号量
            countDownLatch = new CountDownLatch(1);
            try {
                // 等待
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 删除事件通知
        zkClient.unsubscribeDataChanges(PATH,iZkDataListener);
    }

    /**
     * 是否获取锁成功,成功返回true,失败返回false
     */
    @Override
    Boolean tryLock() {
        try {
            zkClient.createEphemeral(PATH);
            return true;
        } catch (RuntimeException e) {
            return false;
        }
    }
}
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 生成订单号规则 使用时间戳+业务id
 * Created by yz on 2018/4/7.
 */
public class OrderNumGenerator {
    // 业务ID
    private static int count = 0;
    //生成订单号
    public String getNumber(){
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        return simpleDateFormat.format(new Date())+"_"+ ++count;
    }
}
/**
 * 订单生成调用业务逻辑
 * Created by yz on 2018/4/7.
 */
public class OrderService implements Runnable{

    // 生成订单号
    OrderNumGenerator orderNumGenerator = new OrderNumGenerator();

    // 使用zk分布式锁
    private Lock lock = new ZookeeperDistrbuteLock();

    @Override
    public void run() {
        try {
            //上锁
            lock.getLock();
            getNumber();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // 是否锁资源
            lock.unLock();
        }
    }
    public void getNumber(){
        String number = orderNumGenerator.getNumber();
        System.out.println(Thread.currentThread().getName()+",##number:"+number);
    }

    public static void main(String[] args) {
        System.out.println("#模拟生成订单号...");
        for (int i = 0; i < 100; i++) {
            new Thread(new OrderService()).start();
        }
    }
}



猜你喜欢

转载自blog.csdn.net/yz2015/article/details/79777394