1.分布式共享锁的简单实现

  在分布式系统中如何对进程进行调度,假设在第一台机器上挂载了一个资源,然后这三个物理分布的进程都要竞争这个资源,但我们又不希望他们同时

进行访问,这时候我们就需要一个协调器,来让他们有序的来访问这个资源。这个协调器就是我们经常提到,比如说"进程-1"在使用该资源的时候,会先去

获得锁,"进程1"获得锁以后会对该资源保持独占,这样其他进程就无法访问该资源,"进程1"用完该资源以后就将锁释放掉,让其他进程来获得锁,那么通过这

锁机制,我们就能保证了分布式系统中多个进程能够有序的访问该临界资源。那么我们把这个分布式环境下的这个锁叫作分布式锁。这个分布式锁也就是我们

分布式协调技术实现的核心内容,那么如何实现这个分布式呢?

  

  分布式协调技术主要用来解决分布式环境当中多个进程之间的同步控制,让他们有序的去访问某种临界资源,防止造成"脏数据"的后果

代码实现:分布式多进程模式实现

import java.util.Collections;
import java.util.List;
import java.util.Random; 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; public class DistributedClientLock {
// 会话超时
private static final int SESSION_TIMEOUT = 2000;
// zookeeper集群地址
private String hosts = "shizhan2:2183,shizhan3:2183,shizhan5:2183";
private String groupNode = "locks";
private String subNode = "sub";
private boolean haveLock = false;
private ZooKeeper zk;
// 记录自己创建的子节点路径
private volatile String thisPath; /**
* 连接zookeeper
*/
public void connectZookeeper() throws Exception {
zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {
public void process(WatchedEvent event) {
try {
System.out.println("=============事件监听=============");
// 判断事件类型,此处只处理子节点变化事件
if (event.getType() == EventType.NodeChildrenChanged && event.getPath().equals("/" + groupNode)) {
//获取子节点,并对父节点进行监听
List<String> childrenNodes = zk.getChildren("/" + groupNode, true);
String thisNode = thisPath.substring(("/" + groupNode + "/").length());
System.out.println("thisNode------"+thisNode);
// 去比较是否自己是最小id
Collections.sort(childrenNodes);
System.out.println("childrenNodes.indexOf(thisNode)"+childrenNodes.indexOf(thisNode));
if (childrenNodes.indexOf(thisNode) == 0) {
//访问共享资源处理业务,并且在处理完成之后删除锁
doSomething();
//重新注册一把新的锁
thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}); // 1、程序一进来就先注册一把锁到zk上
thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL); // wait一小会,便于观察
Thread.sleep(new Random().nextInt(1000)); // 从zk的锁父目录下,获取所有子节点,并且注册对父节点的监听
List<String> childrenNodes = zk.getChildren("/" + groupNode, true); //如果争抢资源的程序就只有自己,则可以直接去访问共享资源
if (childrenNodes.size() == 1) {
System.out.println("当前服务器数目:"+childrenNodes.size());
doSomething();
thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
}
} /**
* 处理业务逻辑,并且在最后释放锁
*/
private void doSomething() throws Exception {
try {
System.out.println("gain lock: " + thisPath);
Thread.sleep(2000);
// do something
} finally {
System.out.println("finished: " + thisPath);
zk.delete(this.thisPath, -1);
}
} public static void main(String[] args) throws Exception {
DistributedClientLock dl = new DistributedClientLock();
dl.connectZookeeper();
Thread.sleep(Long.MAX_VALUE);
}
}

代码实现2:

import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch; 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.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat; public class DistributedClientLock {
// 超时时间
private static final int SESSION_TIMEOUT = 5000;
// zookeeper server列表
private String hosts = "shizhan2:2183,shizhan3:2183,shizhan5:2183";
private String groupNode = "locks";
private String subNode = "sub"; private ZooKeeper zk;
// 当前client创建的子节点
private String thisPath;
// 当前client等待的子节点
private String waitPath; private CountDownLatch latch = new CountDownLatch(1); /**
* 连接zookeeper
*/
public void connectZookeeper() throws Exception {
zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {
public void process(WatchedEvent event) {
try {
// 连接建立时, 打开latch, 唤醒wait在该latch上的线程
if (event.getState() == KeeperState.SyncConnected) {
latch.countDown();
} // 发生了waitPath的删除事件
if (event.getType() == EventType.NodeDeleted && event.getPath().equals(waitPath)) {
doSomething();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}); // 等待连接建立
latch.await(); // 创建子节点
thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL); // wait一小会, 让结果更清晰一些
Thread.sleep(10); // 注意, 没有必要监听"/locks"的子节点的变化情况
List<String> childrenNodes = zk.getChildren("/" + groupNode, false); // 列表中只有一个子节点, 那肯定就是thisPath, 说明client获得锁
if (childrenNodes.size() == 1) {
doSomething();
} else {
String thisNode = thisPath.substring(("/" + groupNode + "/").length());
// 排序
Collections.sort(childrenNodes);
int index = childrenNodes.indexOf(thisNode);
if (index == -1) {
// never happened
} else if (index == 0) {
// inddx == 0, 说明thisNode在列表中最小, 当前client获得锁
doSomething();
} else {
// 获得排名比thisPath前1位的节点
this.waitPath = "/" + groupNode + "/" + childrenNodes.get(index - 1);
// 在waitPath上注册监听器, 当waitPath被删除时, zookeeper会回调监听器的process方法
zk.getData(waitPath, true, new Stat());
}
}
} private void doSomething() throws Exception {
try {
System.out.println("gain lock: " + thisPath);
Thread.sleep(2000);
// do something
} finally {
System.out.println("finished: " + thisPath);
// 将thisPath删除, 监听thisPath的client将获得通知
// 相当于释放锁
zk.delete(this.thisPath, -1);
}
} public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
new Thread() {
public void run() {
try {
DistributedClientLock dl = new DistributedClientLock();
dl.connectZookeeper();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
} Thread.sleep(Long.MAX_VALUE);
}}

时序图:

  

8.6.zookeeper应用案例_分布式共享锁的简单实现的更多相关文章

  1. 8.5.zookeeper应用案例_分布式应用HA

    1.实现分布式应用(主节点HA)及客户端动态更新主节点状态 需求:某分布式系统中,主节点可以有多台,服务器可以动态(变化)上下线,任意一台客户端都能实时感知到主节点服务器的上下线 思路:架设Zooke ...

  2. ZooKeeper 分布式共享锁的实现

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

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

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

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

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

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

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

  6. Dubbo+zookeeper构建高可用分布式集群(二)-集群部署

    在Dubbo+zookeeper构建高可用分布式集群(一)-单机部署中我们讲了如何单机部署.但没有将如何配置微服务.下面分别介绍单机与集群微服务如何配置注册中心. Zookeeper单机配置:方式一. ...

  7. ZooKeeper 3.5.0 分布式配置问题

    ZooKeeper 3.5.0 分布式配置好后,执行./zkServer.sh start 命令启动,报如下错误: 2015-07-02 21:06:01,671 [myid:] - INFO [ma ...

  8. 简单之美 | ZooKeeper应用案例

    简单之美 | ZooKeeper应用案例 ZooKeeper应用案例

  9. 学习笔记:Zookeeper 应用案例(上下线动态感知)

    1.Zookeeper 应用案例(上下线动态感知) 8.1 案例1--服务器上下线动态感知 8.1.1 需求描述 某分布式系统中,主节点可以有多台,可以动态上下线 任意一台客户端都能实时感知到主节点服 ...

随机推荐

  1. Product - 产品经理 - 转型

    特别说明 本文是已读书籍的学习笔记和内容摘要,原文内容有少部分改动,并添加一些相关信息,但总体不影响原文表达. - ISBN: 9787568041591 - https://book.douban. ...

  2. 在centos卸载mysql

    1 rpm -qa|grep mysql 查看安装了哪些mysql和lib…… 1 yum remove mysql mysql-server mysql-libs compat-mysql51 删除 ...

  3. 机器学习笔记——模型调参利器 GridSearchCV(网格搜索)参数的说明

    GridSearchCV,它存在的意义就是自动调参,只要把参数输进去,就能给出最优化的结果和参数.但是这个方法适合于小数据集,一旦数据的量级上去了,很难得出结果.这个时候就是需要动脑筋了.数据量比较大 ...

  4. Linux文件属性之软硬连接知识深度详解

    一.链接的概念 在Linux系统中,链接可分为两种:一种为硬链接(Hard Link),另一个位软连接或符号链接(Symbolic Link or link).我们在前面讲解过ln这个命令就是创建链接 ...

  5. Redis(1.9)Redis主从复制

    [1]实验环境 CentOS7.5 + Redis4.0.11 架构:原生1主2从,做实验机器有限,从库双实例 主库:192.168.135.170 从库1:192.168.135.171~6379 ...

  6. Java判断指定日期是否为工作日

    Java判断指定日期是否为工作日 转自:https://www.jianshu.com/p/966659492f2f 转:https://www.jianshu.com/p/05ccb5783f65转 ...

  7. Centos7 + nginx 托管 Django 项目

    使用nginx托管django服务的原理 使用uwsgi开启django服务(通过配置文件启动) 防火墙关闭uwsgi端口(uwsgi的websocket一定要使用127.0.0.1的方式配置)) 编 ...

  8. php 正则替换特殊字符 和检测是否是中文

    如果是只想输入中文的话,就这么写,要注意是分gb2312和utf-8的哦: gb2312:if(!preg_match("/^[".chr(0xa1)."-". ...

  9. readlink、find-exec参数、file命令

    一.readlink:查看符号链接文件的内容 语法       readlink [选项] ...文件... 描述       打印符号链接或规范文件名的值 -f,--canonicalize     ...

  10. C++入门基础知识(一)

    一:关键字 在C语言中,我们已经学习过了很多的关键字,例如:static,struct等,下面展现一下C++中的一些关键字. 二:命名空间 在C/C++中,变量.函数和类都是大量存在的,这些变量.函数 ...