zoukankan      html  css  js  c++  java
  • 基于zookeeper实现的分布式锁

    <header class="entry-header">
    			<h1 class="entry-title" itemprop="name headline">基于zookeeper实现的分布式锁</h1>
    	
    	<div class="entry-meta">
    		<time class="entry-date" datetime="2011-01-27T01:37:13+00:00" pubdate="" itemprop="datePublished">2011-01-27</time> <span class="dot">•</span> <span class="categories-links" itemprop="keywords"><a href="http://www.jiacheo.org/cat/tech" rel="category tag">技术</a></span> <span class="dot">•</span> <a href="http://www.jiacheo.org/blog/122#comments" class="comments-link">7 条评论</a> <span class="dot">•</span> <a class="author vcard" itemprop="author" itemscope="" itemtype="http://schema.org/Person" rel="author" href="http://www.jiacheo.org/blog/author/jiacheo"><span itemprop="name" class="fn">jiacheo</span></a> <span class="dot">•</span>14,941 阅读		</div>
    </header>
    
    		<div class="entry-content" itemprop="articleBody">
    			<p>A distributed lock base on <a title="zookeeper" href="http://hadoop.apache.org/zookeeper/" target="_blank">zookeeper</a>.</p>
    

    zookeeper是hadoop下面的一个子项目, 用来协调跟hadoop相关的一些分布式的框架, 如hadoop, hive, pig等, 其实他们都是动物, 所以叫zookeeper(本人歪歪).

    zookeeper其实是集群中每个节点都维护着一棵相同的树, 树的结构跟linux的目录结构的概念差不多, 以/为跟节点, 下边可以扩展任意的节点和叶子节点, 每个节点都可以写入数据. 基于zookeeper的分布式锁的实现, 其实是得益于zookeeper同步文件的强大性, 我们相信每时每刻我们访问zookeeper的树时, 相同节点返回的数据都是一致的. 这要靠zookeeper内部的一些算法来实现. 特别是leader的选举算法, 这里就不说了, 感兴趣的话可以去搜索一下看看.

    我们知道了zookeeper集群的每个节点的数据都是一致的, 那么我们可以通过这些节点来作为锁的标志.

    首先给锁设置一下API, 至少要包含, lock(锁住), unlock(解锁), isLocked(是否锁住)三个方法

    然后我们可以创建一个工厂(LockFactory), 用来专门生产锁.

    锁的创建过程如下描述:

    前提:每个锁都需要一个路径来指定(如:/jiacheo/lock)

    1.根据指定的路径, 查找zookeeper集群下的这个节点是否存在.(说明已经有锁了)

    2. 如果存在, 根据查询者的一些特征数据(如ip地址/hostname), 当前的锁是不是查询者的

    3. 如果不是查询者的锁, 则返回null, 说明创建锁失败

    4. 如果是查询者的锁, 则把这个锁返回给查询者

    5. 如果这个节点不存在, 说明当前没有锁, 那么创建一个临时节点, 并将查询者的特征信息写入这个节点的数据中, 然后返回这个锁.

    根据以上5部, 一个分布式的锁就可以创建了.

    创建的锁有三种状态:

    1. 创建失败(null), 说明该锁被其他查询者使用了.'

    2. 创建成功, 但当前没有锁住(unlocked), 可以使用

    3. 创建成功, 但当前已经锁住(locked)了, 不能继续加锁.

    distrib lock

    如图, 如果我们getLock("/jiacheo/lock1","192.168.0.100"), 想要获取/jiacheo/lock1这个锁的话, 我们先判断这个节点是否存在, 存在的话获取他的数据(data), 然后通过解析data, 我们可以知道这个节点是不是我们查询者创建的(通过ip地址写入节点数据中), 然后就可以返回一个锁了.

    具体的java实现(implementation)代码如下:
    1. Lock.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    package org.jiacheo.zkdl.lock;
     
    import java.net.InetAddress;
    import java.net.UnknownHostException;
     
    import org.apache.zookeeper.KeeperException;
    import org.apache.zookeeper.ZooKeeper;
    import org.apache.zookeeper.data.Stat;
     
    /**
     * 类名:<b>Lock</b> <br/>
     * <p>
     * 类描述:
     * </p>
     * 创建人:jiacheo <br/>
     * 创建时间:2011-1-27 上午01:30:25  <br/> 
     * @version 2011-1-27 
     *
     */
    public class Lock {
        private String path;
        private ZooKeeper zooKeeper;
        public Lock(String path){
            this.path = path;
        }
         
        /**
         * <p>
         * 方法描述: 上锁 lock it
         * </p>
         * 创建人:jiacheo <br/>
         * 创建时间:2011-1-27 上午01:30:50  <br/>
         * @throws Exception
         */
        public synchronized void lock() throws Exception{
            Stat stat = zooKeeper.exists(path, true);
            String data = InetAddress.getLocalHost().getHostAddress()+":lock";
            zooKeeper.setData(path, data.getBytes(), stat.getVersion());
        }
         
        /**
         * <p>
         * 方法描述:开锁 unlock it
         * </p>
         * 创建人:jiacheo <br/>
         * 创建时间:2011-1-27 上午01:31:20  <br/>
         * @throws Exception
         */
        public synchronized void unLock() throws Exception{
            Stat stat = zooKeeper.exists(path, true);
            String data = InetAddress.getLocalHost().getHostAddress()+":unlock";
            zooKeeper.setData(path, data.getBytes(), stat.getVersion());
        }
         
        /**
         * <p>
         * 方法描述:是否锁住了, isLocked?
         * </p>
         * 创建人:jiacheo <br/>
         * 创建时间:2011-1-27 上午01:31:43  <br/>
         * @return
         */
        public synchronized boolean isLock(){
            try {
                Stat stat = zooKeeper.exists(path, true);
                String data = InetAddress.getLocalHost().getHostAddress()+":lock";
                String nodeData = new String(zooKeeper.getData(path, true, stat));
                if(data.equals(nodeData)){
    //              lock = true;
                    return true;
                }
            } catch (UnknownHostException e) {
                // ignore it
            } catch (KeeperException e) {
                //TODO use log system and throw a new exception
            } catch (InterruptedException e) {
                // TODO use log system and throw a new exception
            }
            return false;
        }
     
        public String getPath() {
            return path;
        }
     
        public void setPath(String path) {
            this.path = path;
        }
     
        public void setZooKeeper(ZooKeeper zooKeeper) {
            this.zooKeeper = zooKeeper;
        }
         
         
    }

    2.LockFactory.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    package org.jiacheo.zkdl.lock;
     
    import java.io.IOException;
    import java.net.InetAddress;
    import java.util.Collections;
     
    import org.apache.zookeeper.CreateMode;
    import org.apache.zookeeper.WatchedEvent;
    import org.apache.zookeeper.Watcher;
    import org.apache.zookeeper.ZooKeeper;
    import org.apache.zookeeper.ZooDefs.Ids;
    import org.apache.zookeeper.ZooDefs.Perms;
    import org.apache.zookeeper.data.ACL;
    import org.apache.zookeeper.data.Stat;
     
    public class LockFactory {
         
        public static final ZooKeeper DEFAULT_ZOOKEEPER = getDefaultZookeeper();
        //data格式:  ip:stat  如: 10.232.35.70:lock 10.232.35.70:unlock
        public static synchronized Lock getLock(String path,String ip) throws Exception{
            if(DEFAULT_ZOOKEEPER != null){
                Stat stat = null;
                try{
                    stat = DEFAULT_ZOOKEEPER.exists(path, true);
                }catch (Exception e) {
                    // TODO: use log system and throw new exception
                }
                if(stat!=null){
                    byte[] data = DEFAULT_ZOOKEEPER.getData(path, null, stat);
                    String dataStr = new String(data);
                    String[] ipv = dataStr.split(":");
                    if(ip.equals(ipv[0])){
                        Lock lock = new Lock(path);
                        lock.setZooKeeper(DEFAULT_ZOOKEEPER);
                        return lock;
                    }
                    //is not your lock, return null
                    else{
                        return null;
                    }
                }
                //no lock created yet, you can get it
                else{
                    createZnode(path);
                    Lock lock = new Lock(path);
                    lock.setZooKeeper(DEFAULT_ZOOKEEPER);
                    return lock;
                }
            }
            return null;
        }
         
        private static ZooKeeper getDefaultZookeeper() {
            try {
                ZooKeeper zooKeeper = new ZooKeeper("10.232.35.72", 10*1000, new Watcher(){
                    public void process(WatchedEvent event) {
                        //节点的事件处理. you can do something when the node's data change
    //                  System.out.println("event " + event.getType() + " has happened!");
                    }
                });
                return zooKeeper;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
     
        private static void createZnode(String path) throws Exception{
             
            if(DEFAULT_ZOOKEEPER!=null){
                InetAddress address = InetAddress.getLocalHost();
                String data = address.getHostAddress()+":unlock";
                DEFAULT_ZOOKEEPER.create(path, data.getBytes(),Collections.singletonList(new ACL(Perms.ALL,Ids.ANYONE_ID_UNSAFE)) , CreateMode.EPHEMERAL);
            }
        }
    }
    	<footer class="entry-footer">
    			<span class="tags-links" itemprop="keywords"><a href="http://www.jiacheo.org/tag/distributed-lock" rel="tag">Distributed lock</a><a href="http://www.jiacheo.org/tag/java" rel="tag">java</a><a href="http://www.jiacheo.org/tag/zookeeper" rel="tag">zookeeper</a></span>		<div class="copyright">原创文章转载请注明:转载自:<a href="http://www.jiacheo.org/blog/122">基于zookeeper实现的分布式锁</a></div><div id="wumiiDisplayDiv"></div>	</footer>
    
    </article>
查看全文
  • 相关阅读:
    log4j 配置文件
    log4j安装与简介
    tomcat服务
    查看系统网络连接打开端口、系统进程、DOS打开文件
    find查找指定类型文件并删除
    git/github在windows上使用
    VIM配置自动提示功能
    VIM Taglist安装配置和使用
    python Scipy积分运算大全(integrate模块——一重、二重及三重积分)
    python matplotlib绘图大全(散点图、柱状图、饼图、极坐标图、热量图、三维图以及热图)
  • 原文地址:https://www.cnblogs.com/jpfss/p/8243961.html
  • Copyright © 2011-2022 走看看