原创播客,如需转载请注明出处。原文地址:http://www.cnblogs.com/crawl/p/8352919.html

----------------------------------------------------------------------------------------------------------------------------------------------------------

笔记中提供了大量的代码示例,需要说明的是,大部分代码示例都是本人所敲代码并进行测试,不足之处,请大家指正~

本博客中所有言论仅代表博主本人观点,若有疑惑或者需要本系列分享中的资料工具,敬请联系 qingqing_crawl@163.com

GitHub:https://github.com/QingqingQi

-----------------------------------------------------------------------------------------------------------------------------------------------------------

前言:ZooKeeper 是提供少量数据存储和管理的分布式协调服务。适合存储状态管理信息,可以进行数据的读写,同步,提供对数据节点的监听功能。利用 ZooKeeper 可以实现很多功能,比如:Hadoop2.0,使用 Zookeeper 的事件处理确保整个集群只有一个活跃的 NameNode,存储配置信息等;可以利用 ZooKeeper 感知集群中哪台主机宕机或者下线等等。今天介绍另一个常用的功能,利用 Zookeeper 实现分布式共享锁。

一、简要介绍

利用 Zookeeper 实现分布式共享锁,可以做到一次只有指定个数的客户端访问服务器的某些资源。

二、实现步骤

利用 Zookeeper 实现分布式共享锁的步骤大致可以分为以下几步:

1. 客户端上线即向 Zookeeper 注册,创建一把锁

2. 判断是否只有一个客户端工作,若只有一个客户端工作,此客户端可以处理业务

3. 获取父节点下注册的所有锁,通过判断自己是否是号码最小的那一把锁,若是则可以处理业务,否则等待

值的注意的是,在某一客户端获取到锁处理完业务后,必须释放锁

三、实现代码

1. 新建一个 DistributedLock 类

private ZooKeeper zkClient = null;

    //连接字符串
private static final String connectString = "zookeeper01:2181,zookeeper02:2181,zookeeper03:2181"; //超时时间
private static final int sessionTimeout = 2000; //父节点
private static final String parentNode = "/locks"; //记录自己创建子节点的路径
private volatile String thisPath; public static void main(String[] args) throws Exception {
//1.获取 ZooKeeper 的客户端连接
DistributedLock distLock = new DistributedLock();
distLock.getZKClient(); //2.注册一把锁
distLock.regiestLock(); //3.监听父节点,判断是否只有自己在线
distLock.watchParent();
}

2. main 方法中定义了三个方法

1)getZKClient():用来获取 Zookeeper 客户端的连接

其中 process 方法是当监听节点发生变化时调用,其中获取定义的父节点的所有子节点,然后判断当前节点是否是最小节点,若是则进行业务逻辑处理阶段,并重新注册一把新的锁

//获取 zk 客户端
public void getZKClient() throws Exception {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() { @Override
public void process(WatchedEvent event) {
//判断事件类型,只处理子节点变化事件
if(event.getType() == EventType.NodeChildrenChanged && event.getPath().equals(parentNode)) {
try {
List<String> childrens = zkClient.getChildren(parentNode, true);
//判断自己是否是最小的
String thisNode = thisPath.substring((parentNode + "/").length());
Collections.sort(childrens);
if(childrens.indexOf(thisNode) == 0){
//处理业务逻辑
dosomething();
//重新注册一把新的锁
thisPath = zkClient.create(parentNode + "/lock", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}

2)main 中的第二个方法是 rediestLock()

调用 Zookeeper 客户端的 create() 方法,建立一个新的节点

//注册一把锁
public void regiestLock() throws Exception {
thisPath = zkClient.create(parentNode + "/lock", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
}

3)第三个是 watchParent() 方法

在此方法中判断是否只有一个节点在线,若只有自己一个节点,则调用业务处理的方法

//监听父节点,判断是否只有自己在线
public void watchParent() throws Exception {
List<String> childrens = zkClient.getChildren(parentNode, true);
if (childrens != null && childrens.size() == 1) {
//只有自己在线,处理业务逻辑(处理完业务逻辑,必须删释放锁)
dosomething();
} else {
//不是只有自己在线,说明别人已经获取到锁,等待
Thread.sleep(Long.MAX_VALUE);
}
}

4)最后一个是自定义的业务逻辑方法

需要注意的是,当处理完业务逻辑后,必须释放锁

//业务逻辑方法,注意:需要在最后释放锁
public void dosomething() throws Exception {
System.out.println("或得到锁:" + thisPath);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("释放锁:" + thisPath);
zkClient.delete(thisPath, -1);
}
}

3. 最后贴一下全部代码

package com.software.bigdata.zkdistlock;

import java.util.Collections;
import java.util.List; import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper; /**
* @Description: 分布式共享锁
*
* @author Crawl
* @date 2018年1月25日 下午5:02:42
*/
public class DistributedLock { private ZooKeeper zkClient = null; //连接字符串
private static final String connectString = "zookeeper01:2181,zookeeper02:2181,zookeeper03:2181"; //超时时间
private static final int sessionTimeout = 2000; //父节点
private static final String parentNode = "/locks"; //记录自己创建子节点的路径
private volatile String thisPath; public static void main(String[] args) throws Exception {
//1.获取 ZooKeeper 的客户端连接
DistributedLock distLock = new DistributedLock();
distLock.getZKClient(); //2.注册一把锁
distLock.regiestLock(); //3.监听父节点,判断是否只有自己在线
distLock.watchParent();
} //业务逻辑方法,注意:需要在最后释放锁
public void dosomething() throws Exception {
System.out.println("或得到锁:" + thisPath);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("释放锁:" + thisPath);
zkClient.delete(thisPath, -1);
}
} //监听父节点,判断是否只有自己在线
public void watchParent() throws Exception {
List<String> childrens = zkClient.getChildren(parentNode, true);
if (childrens != null && childrens.size() == 1) {
//只有自己在线,处理业务逻辑(处理完业务逻辑,必须删释放锁)
dosomething();
} else {
//不是只有自己在线,说明别人已经获取到锁,等待
Thread.sleep(Long.MAX_VALUE);
}
} //注册一把锁
public void regiestLock() throws Exception {
thisPath = zkClient.create(parentNode + "/lock", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
} //获取 zk 客户端
public void getZKClient() throws Exception {
zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() { @Override
public void process(WatchedEvent event) {
//判断事件类型,只处理子节点变化事件
if(event.getType() == EventType.NodeChildrenChanged && event.getPath().equals(parentNode)) {
try {
List<String> childrens = zkClient.getChildren(parentNode, true);
//判断自己是否是最小的
String thisNode = thisPath.substring((parentNode + "/").length());
Collections.sort(childrens);
if(childrens.indexOf(thisNode) == 0){
//处理业务逻辑
dosomething();
//重新注册一把新的锁
thisPath = zkClient.create(parentNode + "/lock", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
} }

ZooKeeper 分布式共享锁的实现的更多相关文章

  1. Zookeeper使用实例——分布式共享锁

    前一讲中我们知道,Zookeeper通过维护一个分布式目录数据结构,实现分布式协调服务.本文主要介绍利用Zookeeper有序目录的创建和删除,实现分布式共享锁. 举个例子,性能管理系统中,告警规则只 ...

  2. zookeeper编程入门系列之zookeeper实现分布式进程监控和分布式共享锁(图文详解)

    本博文的主要内容有 一.zookeeper编程入门系列之利用zookeeper的临时节点的特性来监控程序是否还在运行   二.zookeeper编程入门系列之zookeeper实现分布式进程监控 三. ...

  3. Zookeeper概念学习系列之zookeeper实现分布式共享锁

    首先假设有两个线程, 两个线程要同时到mysql中更新一条数据, 对数据库中的数据进行累加更新.由于在分布式环境下, 这两个线程可能存在于不同的机器上的不同jvm进程中, 所以这两个线程的关系就是垮主 ...

  4. 8.6.zookeeper应用案例_分布式共享锁的简单实现

    1.分布式共享锁的简单实现 在分布式系统中如何对进程进行调度,假设在第一台机器上挂载了一个资源,然后这三个物理分布的进程都要竞争这个资源,但我们又不希望他们同时 进行访问,这时候我们就需要一个协调器, ...

  5. ZooKeeper 分布式锁实现

    1 场景描述 在分布式应用, 往往存在多个进程提供同一服务. 这些进程有可能在相同的机器上, 也有可能分布在不同的机器上. 如果这些进程共享了一些资源, 可能就需要分布式锁来锁定对这些资源的访问. 2 ...

  6. zookeeper 分布式锁原理

    zookeeper 分布式锁原理: 1 大家也许都很熟悉了多个线程或者多个进程间的共享锁的实现方式了,但是在分布式场景中我们会面临多个Server之间的锁的问题,实现的复杂度比较高.利用基于googl ...

  7. Hadoop Zookeeper 分布式服务框架

    what is Zookeeper? 1,开源的分布式的,为分布式应用提供协调服务的Apache项目2,提供一个简单原语集合,以便于分布式应用可以在它之上构建更高层次的同步服务3,设计非常易于编程,它 ...

  8. Curator Zookeeper分布式锁

    Curator Zookeeper分布式锁 pom.xml中添加如下配置 <!-- https://mvnrepository.com/artifact/org.apache.curator/c ...

  9. Zookeeper分布式集群搭建

    实验条件:3台安装linux的机子,配置好Java环境. 步骤1:下载并分别解包到每台机子的/home/iHge2k目录下,附上下载地址:http://mirrors.cnnic.cn/apache/ ...

随机推荐

  1. npm lodash

    在数据操作时,Lodash 就是我的弹药库,不管遇到多复杂的数据结构都能用一些函数轻松拆解. ES6 中也新增了诸多新的对象函数,一些简单的项目中 ES6 就足够使用了,但还是会有例外的情况引用了少数 ...

  2. VC6.0 突然打不开dsw 工程文件的解决方案

    在vc编程中,经常遇到dsw工程文件无法打开,或者打开后看不到类和变量的问题.特别是把代码从一台电脑上copy到另一台电脑上以后,常常会碰到这种奇怪的问题.有时在编辑状态下也会发生成员变量或函数提示不 ...

  3. 解决SVN造成的桌面图标问号

    之前不小心直接将版本库 的内容检出 到桌面,后才发现桌面上的文件 都变成了问号,本来也以为没有多大问题,删除.svn 即可,可是删除所有的.svn后,桌面上还是显示问号,刷新了很多次,还重启电脑 了, ...

  4. IDA Pro反编译代码类型转换参考

    /* This file contains definitions used by the Hex-Rays decompiler output. It has type definitions an ...

  5. Java笔记:Java 流(Stream)、文件(File)和IO

    更新时间:2018-1-7 12:27:21 更多请查看在线文集:http://android.52fhy.com/java/index.html java.io 包几乎包含了所有操作输入.输出需要的 ...

  6. Jenkins 学习笔记(二):很简单的发布一次

    发布思路:从 github 拉取一些文件,然后推送到 Target server 的某个目录. 准备 1. Jenkins 需要安装的插件:『 Publish over SSH 』 2. 全局配置:系 ...

  7. linux系统编程:自己动手写一个who命令

    who命令的作用用于显示当前有哪些用户登录到系统. 这个命令执行的原理是读取了系统上utmp文件中记录的所有登录信息,直接显示出来的 utmp文件在哪里呢? man who的时候,在手册下面有这么一段 ...

  8. Heroku 如何上重置 PostgreSQL 数据库

      如果你要在 Heroku 上重置 PostgreSQL 数据库,可以使用以下命令 : $ heroku pg:reset DATABASE $ heroku run php artisan mig ...

  9. SSM框架开发web项目系列(五) Spring集成MyBatis

    前言 在前面的MyBatis部分内容中,我们已经可以独立的基于MyBatis构建一个数据库访问层应用,但是在实际的项目开发中,我们的程序不会这么简单,层次也更加复杂,除了这里说到的持久层,还有业务逻辑 ...

  10. ubuntu16.04+eigen3安装

    Eigen库安装指南(两种方式)1.apt-get方式(假设默认安装到/usr/local/include里,若实际中默认安装到了/usr/include的话,可以对应替换下面命令的相应部分);运行命 ...