【Zookeeper】基于Zookeeper实现分布式锁
1.概述
转载:基于Zookeeper实现分布式锁
1.1 为什么使用分布式锁
我们在开发应用的时候,如果需要对某一个共享变量进行多线程同步访问的时候,我们往往采用synchronized或者Lock的方解决多线程的代码同步问题,这时多线程的运行是在同一个JVM之下是没有任何问题的。
但当我们的应用是分布式集群工作的情况下,属于多JVM下的工作环境,跨JVM之间已经无法通过多线程的锁解决同步问题。
那么就需要一种更加高级的锁机制,来处理跨机器的进程之间的数据同步问题——分布式锁。
分布锁的实现方式有三种:
基于数据库实现分布式锁
基于缓存(Redis等)实现分布式锁
基于Zookeeper实现分布式锁
今天我们讨论一下基于Zookeeper实现分布式锁的原理。
1.2 分布式锁应具备的条件
1、在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行;
2、高可用的获取锁与释放锁;
3、高性能的获取锁与释放锁;
4、具备可重入特性;
5、具备锁失效机制,防止死锁;
6、具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。
1.3 实现过程原理
核心思想:当客户端要获取锁,则创建临时顺序节点,使用完锁,则删除该节点。
1.3.1 获取锁
首先,在Zookeeper当中创建一个持久节点Lock。当第一个客户端想要获得锁时,需要在Lock这个节点下面创建一个临时顺序节点 Lock1
之后,Client1查找Lock下面所有的临时顺序节点并比较排序,判断自己所创建的节点Lock1是不是序号最小的哪一个。如果是,则成功获得锁。
这时候,如果再有一个客户端 Client2 前来获取锁,则在Lock下载再创建一个临时顺序节点Lock2。
Client2查找Lock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock2是不是序号最小的那个,结果发现节点Lock2并不是最小的。
于是,Client2向排序仅比它靠前的节点Lock1注册Watcher事件监听器,监听删除事件,用于监听Lock1节点是否存在。这意味着Client2抢锁失败,进入了等待状态。
这时候,如果又有一个客户端Client3前来获取锁,则在Lock下载再创建一个临时顺序节点Lock3。
Client3查找Lock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock3是不是序号最小的那个,结果同样发现节点Lock3并不是最小的。
于是,Client3向排序仅比它靠前的节点Lock2注册Watcher,用于监听Lock2节点是否存在。这意味着Client3同样抢锁失败,进入了等待状态。
这样一来,Client1得到了锁,Client2监听了Lock1,Client3监听了Lock2。这恰恰形成了一个等待队列,很像是Java当中ReentrantLock所依赖的。
1.3.2 释放锁
释放锁分为两种情况:
- 任务完成,客户端显示释放 当任务完成时,Client1会显示调用删除节点Lock1的指令。
2.任务执行过程中,客户端崩溃
获得锁的Client1在任务执行过程中,如果Duang的一声崩溃,则会断开与Zookeeper服务端的链接。根据临时节点的特性,相关联的节点Lock1会随之自动删除。
由于Client2一直监听着Lock1的存在状态,当Lock1节点被删除,Client2会立刻收到通知。这时候Client2会再次查询Lock下面的所有节点,确认自己创建的节点Lock2是不是目前最小的节点。如果是最小,则Client2顺理成章获得了锁。
同理,如果Client2也因为任务完成或者节点崩溃而删除了节点Lock2,那么Client3就会接到通知。
最终,Client3成功得到了锁。
2.方案:
可以直接使用zookeeper第三方库Curator客户端,这个客户端中封装了一个可重入的锁服务
Curator提供的InterProcessMutex是分布式锁的实现。acquire方法用户获取锁,release方法用于释放锁。
提供了一个12306的一个抢票小Demo来了解zookeeper分布式锁的实现。
package cn.itcast.test;import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;import java.util.concurrent.TimeUnit;/*需求:模拟车站售票*/
public class Ticket12306 implements Runnable {//票数private int num=50;//声明分布式锁private InterProcessMutex lock;public Ticket12306() {//一旦创建线程任务对象的时候就与zookeeper建立连接RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,2);CuratorFramework client = CuratorFrameworkFactory.builder().connectString("192.168.179.129:2181").retryPolicy(retryPolicy).build();//开启链接client.start();//得到了分布式锁lock = new InterProcessMutex(client,"/lock");}@Overridepublic void run() {while(true){try {//获取锁lock.acquire(3, TimeUnit.SECONDS);//参数一:等待锁的最大超时时间, 参数二;第一个参数的时间单位if(num>0){System.out.println(Thread.currentThread().getName()+"卖出了第"+num+"号票");num--;}else{System.out.println("售罄了..");break;}} catch (Exception e) {e.printStackTrace();}finally {//释放锁try {lock.release();} catch (Exception e) {e.printStackTrace();}}}}public static void main(String[] args) {//创建Runnable实现类对象Ticket12306 ticket = new Ticket12306();//模拟两个窗口售票就是两个线程Thread thread1 = new Thread(ticket,"售票员甲");Thread thread2 = new Thread(ticket,"售票员乙");//开启线程thread1.start();thread2.start();}
}
实际运行效果如下
# 运行前
[zk: localhost:2181(CONNECTED) 16] ls /lock
[]
[zk: localhost:2181(CONNECTED) 17]# 运行中
[zk: localhost:2181(CONNECTED) 5] ls /lock
[_c_53ce1ca4-0732-4337-8778-dca8e570211f-lock-0000000855]
[zk: localhost:2181(CONNECTED) 6] ls /lock
[_c_69ce1f64-84bd-41a4-ab2b-b3dfae3ada0e-lock-0000001120, _c_d5a0c148-75bc-4138-80d5-43908f2222c9-lock-0000001119]
[zk: localhost:2181(CONNECTED) 7] ls /lock
[_c_9be12326-127e-4ef5-96f1-970634772a7d-lock-0000001398]# 结束之后
[zk: localhost:2181(CONNECTED) 16] ls /lock
[]
[zk: localhost:2181(CONNECTED) 17]
M.扩展
ZooKeeper实现分布式锁
【Zookeeper】基于Zookeeper实现分布式锁相关推荐
- Zookeeper和Redis实现分布式锁,附我的可靠性分析
作者:今天你敲代码了吗 链接:https://www.jianshu.com/p/b6953745e341 在分布式系统中,为保证同一时间只有一个客户端可以对共享资源进行操作,需要对共享资源加锁来实现 ...
- 什么是分布式锁?redis、zookeeper、etcd实现分布式锁有什么不同之处?
目录 分布式锁定义 目的 基于redis分布式锁 基于zookeeper实现的分布式锁 edis.zookeeper.etcd实现分布式锁的比较 建议选择etcd实现分布式锁 分布式锁定义 分布式环境 ...
- 关于Zookeeper和Redis实现分布式锁的异同
本文来说下Zookeeper和Redis实现分布式锁的异同 文章目录 概述 Redis单机实现分布式锁 Redis加锁 Redis解锁 Redis加锁过期时间设置问题 Zookeeper单机实现分布式 ...
- etcd 笔记(08)— 基于 etcd 实现分布式锁
1. 为什么需要分布式锁? 在分布式环境下,数据一致性问题一直是个难点.分布式与单机环境最大的不同在于它不是多线程而是多进程.由于多线程可以共享堆内存,因此可以简单地采取内存作为标记存储位置.而多进程 ...
- nx set 怎么实现的原子性_基于Redis的分布式锁实现
前言 本篇文章主要介绍基于Redis的分布式锁实现到底是怎么一回事,其中参考了许多大佬写的文章,算是对分布式锁做一个总结 分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问 ...
- 基于Redis的分布式锁和Redlock算法
来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...
- redis系列:基于redis的分布式锁
一.介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分为两部分,一个是单机环境, ...
- 基于 Redis 的分布式锁到底安全吗?
[完整版] 网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现 ...
- js 拉勾网效果_Node.js 中实践基于 Redis 的分布式锁实现
在一些分布式环境下.多线程并发编程中,如果对同一资源进行读写操作,避免不了的一个就是资源竞争问题,通过引入分布式锁这一概念,可以解决数据一致性问题. 作者简介:五月君,Nodejs Developer ...
- java如何保证redis设置过期时间的原子性_redis专题系列22 -- 如何优雅的基于redis实现分布式锁
几个概念 线程锁:主要用来给方法.代码块加锁.当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段.线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比 ...
最新文章
- SQL_Server_2005_日期和时间函数(描述及实例)
- leetcode - Container With Most Water
- python环境变量配置_Python环境变量的配置
- Linux 开发板4G转WiFi热点 手机连接热点上网(一 思路)
- Animation插值器:解决Android Animation 循环执行的停顿问题
- vr降噪器英文是什么_耳机降噪功能这么多,说说什么是ANC、ENC、CV...
- ubuntu开机时出现“waiting for network configuration” 问题的解决
- 雷达卫星测高原理、最新发展情况
- dubbo教程(绝对的入门到入土)
- 什么是Kodu---Kodu少儿编程第一天
- validity属性返回对象中的属性值
- 用户价值VS商业价值
- final修饰的变量必须初始化吗?
- potplay播放器录制音频
- 第九篇论文读后总结-相似森林
- PHP 微信 扫码登录 pc网站
- Android studio完整安装
- 《计算机网络自顶向下方法》读书笔记(一)
- 微信小程序使用计时器
- 计算机教学论文的主题,计算机英语Web Quest主题教学思路
热门文章
- 预装鸿蒙系统!华为MatePad Pro 2或暂定6月2日发布
- 消息称荣耀7月发布年度旗舰 或用上旗舰级芯片骁龙 888
- 造型奇葩!后置四边角八摄手机曝光:但被吐槽毫无作用
- 绝了,为了压低成本,iPhone 12可能不送这两个配件了
- 华为上架自主地图应用Here WeGo 或登录HMS系统成为预装应用
- 很强势!因拒绝退回用户保证金,知名在线旅游平台成“老赖”,回应...
- 滴滴新规则明日起试行:将影响一大波人
- 5G牌照提前发放 将对整个产业界带来哪些影响?
- 优衣库KAWS联名款遭哄抢 大打出手场面惨烈 是我不懂时尚了吗?
- 苹果AirPower总是跳票的原因找到了?或因商标被抢注