http://www.jiacheo.org/blog/122

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. 基于 Redis 实现的分布式锁

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:我的大学到研究生自学 Java 之路,过程艰辛,不放弃,保持热情,最终发现我是这样拿到大厂 offer 的! 作 ...

  2. 关于Zookeeper来实现分布式锁的几个问题

    本文来说下Zookeeper实现分布式锁的几个问题 文章目录 概述 zk基本锁原理 监听通知机制 zk锁优化原理 zk锁的优缺点 本文小结 概述 zookeeper锁相关基础知识 zookeeper锁 ...

  3. api 创建zookeeper客户端_zookeeper分布式锁原理及实现

    前言 本文介绍下 zookeeper方式 实现分布式锁 原理简介 zookeeper实现分布式锁的原理就是多个节点同时在一个指定的节点下面创建临时会话顺序节点,谁创建的节点序号最小,谁就获得了锁,并且 ...

  4. redistemplate分布式锁实现_基于 Redis SETNX 实现分布式锁

    环境与配置 Redis 任意版本即可 SpringBoot 任意版本即可,但是需要依赖 spring-boot-starter-data-redis <dependency><gro ...

  5. zookeeper java版本号_GitHub - anlijie/java-lock: java版本的用Zookeeper实现的分布式锁

    java-lock java版本的用Zookeeper实现的分布式锁 代码已经测过,可以直接使用! #业务场景 在分布式情况,生成全局订单号ID 生成订单号方案 使用时间戳 使用UUID 推特 (Tw ...

  6. 阿里面试官让我用Zk(Zookeeper)实现分布式锁

    点赞再看,养成习惯,微信搜索[三太子敖丙]关注这个互联网苟且偷生的工具人. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的 ...

  7. java 通过redis实现倒计时_突破Java面试(42) - Redis amp; ZooKeeper两种分布式锁实现的优劣...

    0 Github 1 面试题 一般实现分布式锁都有哪些方式?使用redis如何设计分布式锁?使用zk来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高? 2 考点分析 一般先问问你zk,然后 ...

  8. 基于Redis实现一个分布式锁

    与分布式锁相对应的是「单机锁」,我们在写多线程程序时,避免同时操作一个共享变量产生数据问题,通常会使用一把锁来「互斥」,以保证共享变量的正确性,其使用范围是在「同一个进程」中. 一.为什么需要分布式锁 ...

  9. zookeeper应用之分布式锁

    前一段时间有讨论过用redis来实现分布式锁,讲到setNx不是原子性.redis新的set方法及其误删和守护线程,还为了原子性不得不使用redis的脚本.虽然最终分布式锁的这个效果是实现了,但是,不 ...

最新文章

  1. VS2017更新后 在WIN7上找不到 stdio.h等的问题
  2. 更改git远程分支的方法
  3. 使用 cProfile 和火焰图调优 Python 程序性能
  4. php 0改成百 千_【面试题】小数转换为人民币大写形式,PHP实现。
  5. Vmware迁移datastore注意事项
  6. 深度阅读----人工智能简史及其思维辩证
  7. kotlin入门最容易教程一(最全,最详细)
  8. CorelDRAW2022最新电脑版离线安装教程
  9. 树型选择器/Browsing HDFS筛选文件类型
  10. windows下编译Sqlite-3.38.0及使用(存储json)
  11. pod install 时遇到 Automatically assigning platform `iOS` with version `11.0` on target XXX......
  12. 现在最火爆的盲盒交友小程序源码
  13. 突破微信服务号群发限制
  14. Mysql 分组查询top n(多种方法)
  15. 网络安全学习笔记(2)
  16. 7.python基础之基础数据类型--字典dict
  17. AM335x SPL(一)
  18. Python之报错AttributeError:'CocaCola' object has no attribute 'local_logo'
  19. 社会工程学 | Yandex mail捆绑域名方法
  20. vs2008 创建对话框MFC应用程序调试c++代码

热门文章

  1. 2019年第十届蓝桥杯 - 省赛 - C/C++大学C组 - B. 矩形切割
  2. 《操作系统》CPU如何区分正在运行的是内核程序or应用程序?
  3. 《每日一题》290. Word Pattern
  4. The Triangle
  5. 【Linux】一步一步学Linux——visudo命令(104)
  6. 【Java】Java枚举类型示例
  7. 鸿蒙开发者目前人数,苹果时隔两年公布大中华区开发者数据:440万,增长76%
  8. php中的意外type字符串,关于php:解析错误:语法错误,意外’文本’(T_STRING),期待’,’或’;’...
  9. 360全景html插件,jQuery 360度全景图插件 PANORAMA VIEWER
  10. android win7 共享网络打印机,win7系统设置共享网络打印机的操作方法