A distributed lock base on zookeeper.

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)了, 不能继续加锁.

如图, 如果我们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);
        }
    }

zookeeper实现分布式锁服务的更多相关文章

  1. Zookeeper实现分布式锁服务(Chubby)

    在分布式系统中,如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰,来保证一致性,在这种情况下,便需要使用到分布式锁例如有N台服务器同时 ...

  2. [转载] zookeeper 分布式锁服务

    转载自http://www.cnblogs.com/shanyou/archive/2012/09/22/2697818.html 分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那 ...

  3. zookeeper的分布式锁

    实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...

  4. 基于Zookeeper的分布式锁

    实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...

  5. Zookeeper系列四:Zookeeper实现分布式锁、Zookeeper实现配置中心

    一.Zookeeper实现分布式锁 分布式锁主要用于在分布式环境中保证数据的一致性. 包括跨进程.跨机器.跨网络导致共享资源不一致的问题. 1. 分布式锁的实现思路 说明: 这种实现会有一个缺点,即当 ...

  6. 10分钟看懂!基于Zookeeper的分布式锁

    实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,其中前两种方案网络上有很多资料可以参考,本文不做展开.我们来看下使用Zookeeper如何实现分布式锁. 什么是 ...

  7. ZooKeeper示例 分布式锁

    [转载请注明作者和原文链接,  如有谬误, 欢迎在评论中指正. ] 场景描述 在分布式应用, 往往存在多个进程提供同一服务. 这些进程有可能在相同的机器上, 也有可能分布在不同的机器上. 如果这些进程 ...

  8. 基于ZooKeeper实现——分布式锁与实现

    引言 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...

  9. java就业指南 zookeeper分布式系统 zookeeper实现分布式锁 有用

    目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个 分布式系统都无法同时满足一致性(Consistency).可用性 ...

随机推荐

  1. [deviceone开发]-openPage的动画效果示例

    一.简介do_App的openPage支持16种过场动画,这个示例直观的展示16种动画的效果.适合初学者.二.效果图三.相关下载https://github.com/do-project/code4d ...

  2. Linux 安装基于(PHP5.5)memcache扩展

    一. memcache服务器端 下载地址:http://memcached.org/ 安装memcached,同时需要安装中指定libevent的安装位置 tar zxvf memcached-1.2 ...

  3. React-Native 获取node.js提供的接口

    一个简单的React-Native 获取node.js提供的接口的实现 一.node.js var http = require("http"); var url = requir ...

  4. #include &lt;stdbool.h&gt;

    可以使用bool和true.false 输出是1或者0 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdb ...

  5. CJOJ 血帆海盗

    Description 随着资本的扩大,藏宝海湾贸易亲王在卡利姆多和东部王 国大陆各建立了N/2 个港口.大灾变发生以后,这些港口之间失去了联系,相继脱离了藏宝海湾贸易亲王的管辖,各自为政.利益的驱动 ...

  6. 使用Visual Studio Team Services持续集成(二)——为构建定义属性

    使用Visual Studio Team Services持续集成(二)--为构建定义属性 1.从VSTS帐户进入到Build 2.编辑构建定义并单击Options Description:如果这里明 ...

  7. NumsCount

    package com.home.test; import java.util.Arrays; public class NumsCount { public void getNumCount(int ...

  8. 洛谷 P1984 [SDOI2008]烧水问题 解题报告

    P1984 [SDOI2008]烧水问题 题目描述 把总质量为1kg的水分装在n个杯子里,每杯水的质量均为(1/n)kg,初始温度均为0℃.现需要把每一杯水都烧开.我们可以对任意一杯水进行加热.把一杯 ...

  9. contiki 无线测试 1个中心节点 13个从节点

    1 DATA recv '25.00 degres' from 2423:7c02:5525:4f2b2 DATA recv '27.71 degres' from 24f7:af03:5525:4f ...

  10. POJ 1325 Machine Schedule(最小点覆盖)

    http://poj.org/problem?id=1325 题意: 两种机器A和B.机器A具有n种工作模式,称为mode_0,mode_1,...,mode_n-1,同样机器B有m种工作模式mode ...