zookeeper实现分布式锁

2018-10-13  本文已影响0人  守住阳光

        分布式锁主要解决多个进程访问同一资源时的资源竞争问题。主要有三种解决方案,基于数据库实现分布式锁,基于缓存实现分布式锁和基于zookeeper实现分布式锁。

一、三种实现方案介绍

1、基于数据库实现分布式锁

        基于数据库实现分布式锁实现起来比较简单,但是其有如下缺点:

        (1)性能较差,容易出现单点故障,此由数据库连接池的连接数决定的;

        (2)锁没有失效时间,容易死锁,经常出现的情况是线程死了,数据库记录没有删除,导致出现死锁;

        (3)非阻塞式。

2、基于缓存实现分布式锁

        基于缓存实现分布式锁原理和基于数据库类似,其性能和并发量相较于数据库实现要大大提升,但是也会有如下缺点:

        (1)需要为锁设置失效时间,但是失效时间无法准确设定。

3、基于zookeeper实现分布式锁

        基于zookeeper相较于前面两种方案,其性能和可靠性都有所提升,也是最长采用的方案,其特点如下:

        (1)实现简单;

        (2)可靠性好;

        (3)性能好。

二、zookeeper简介

        zookeeper是一个分布式的、开放源代码的分布式应用程序协调服务,是Hadoop和Hbase的重要组件。在zk中zNode是一个跟Unix或者Windows文件系统路径相似的节点,可以往这个节点存储或者获取数据。

        通过客户端可以对zNode进行增删改查操作,还可以注册watcher监控zNode的变化。zNode跟文件系统一样,名称不可重复。

        zk的节点类型包括:持久节点,持久顺序节点,临时节点,临时顺序节点。临时节点跟会话有关,连接断掉,节点会被自动删除。

三、基于zookeeper实现分布式锁的代码示例

1、定义Lock接口

public interface Lock {

        public void lock();

        public void unLock();

}

2、Lock抽象类(模板模式)     

public abstract class AbstractLock implements Lock{ 

         protected static String host = "127.0.0.1";

         protected static int port = 2181; 

         protected static String path = "/lock"; 

         protected static ZkClient zkClient = new ZkClient(host, port);

         @Override 

         public void lock() { 

             if(tryLock()){

                    System.out.println("获取锁成功!!!");              

             }else{                  

                     //如果尝试获取锁失败,则等待获取锁                 

                     waitForLock();                  

                     lock();              

             } 

        }

         protected abstract boolean tryLock(); 

         protected abstract void waitForLock(); 

 } 

3、锁的具体实现类

public class ZookeeperLock extends AbstractLock{

        private CountDownLatch cdl =null;

        /**

        * 解锁即删除临时节点

        */

        @Override

        public void unLock() {

                zkClient.delete(path);

        }

        /**

        * 如果创建临时节点成表示获取锁成功

        */

        @Override

        protected boolean tryLock() {

            try{

                zkClient.createEphemeral(path);

                return true;

            }catch(Exception e){

                return false ;

            }

        }

        @Override

        protected void waitForLock() {

                IZkDataListener listener = new IZkDataListener(){

                        @Override

                        public void handleDataChange(String dataPath, Object data) throws Exception {

                        }

                        @Override

                        public void handleDataDeleted(String dataPath) throws Exception {

                                //监听临时节点删除事件

                                if(cdl!=null){

                                    cdl.countDown();

                                }

                        }

            };

            //订阅节点改变事件

           zkClient.subscribeDataChanges(path, listener);

           if(zkClient.exists(path)){

                //线程在此阻塞,直到临时节点删除事件触发

                cdl = new CountDownLatch(1);

                try {

                         cdl.await();

                } catch (InterruptedException e) {

                         // TODO Auto-generated catch block

                         e.printStackTrace();

                }

           }

            zkClient.unsubscribeDataChanges(path, listener);

        }

}

上一篇 下一篇

猜你喜欢

热点阅读