利用Zookeeper实现分布式锁
1、分布式锁是什么?
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。
2、为什么需要分布式锁?
在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
3、乐观锁和悲观锁含义
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
本段参考了:http://blog.csdn.net/hongchangfirst/article/details/26004335
4、具体实现
本文采用zookeeper第三方库curator实现分布式锁。
1、添加依赖
<!-- Curator对Zookeeper封装 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.9.1</version>
</dependency> <!-- Curator对Zookeeper封装 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>2.9.1</version>
</dependency> <!-- Curator对Zookeeper封装 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.9.1</version>
</dependency>
2、锁的实现
package com.mao;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry; /**
*
* 项目名称:---
* 模块名称:公共服务-锁工具
* 功能描述:锁工具类(基于Zookeeper)
* 创建人: mao2080@sina.com
* 创建时间:2017年4月20日 下午4:35:56
* 修改人: mao2080@sina.com
* 修改时间:2017年4月20日 下午4:35:56
*/
public class ZKLockUtil { /**Zookeeper注册中心地址*/
private static final String ZOOKEEPER_SERVER; /**获取锁-每次尝试间隔(单位:毫秒)*/
private static final int BASE_SLEEP_TIME = 1000; /**获取锁-最大尝试次数*/
private static final int MAX_RETRIES = 5; /**Curator锁对象*/
private InterProcessMutex lock; /**Curator客户端*/
private CuratorFramework client; /**分布式锁根节点*/
private static final String ZK_BASE_LOCK_PATH = "/Locks/"; /**
* 初始化Zookeeper注册中心地址
*/
static {
ZOOKEEPER_SERVER = "172.24.20.214";
}
/**
*
* 描述:构造函数
* @author mao2080@sina.com
* @created 2017年4月20日 下午3:52:53
* @since
* @param businessType 业务类型
* @param baseSleepTimeMs 获取锁-每次尝试间隔(单位:毫秒)
* @param maxRetries 获取锁-最大尝试次数
* @throws BusinessException
*/
private void initService(BusinessType businessType, int baseSleepTimeMs, int maxRetries) throws Exception {
if(isBlank(ZKLockUtil.ZOOKEEPER_SERVER)){
throw new Exception();
}
if(businessType == null || isBlank(businessType.getCode())){
throw new Exception();
}
try {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(baseSleepTimeMs, maxRetries);
this.client = CuratorFrameworkFactory.newClient(ZKLockUtil.ZOOKEEPER_SERVER, retryPolicy);
this.client.start();
this.setLock(new InterProcessMutex(this.client, ZK_BASE_LOCK_PATH.concat(businessType.getCode())));
} catch (Exception e) {
throw new Exception();
}
} /**
*
* 描述:构造函数
* @author mao2080@sina.com
* @created 2017年4月20日 下午3:52:44
* @since
* @param businessType 业务类型
* @throws BusinessException
*/
public ZKLockUtil(BusinessType businessType) throws Exception {
this.initService(businessType, ZKLockUtil.BASE_SLEEP_TIME, ZKLockUtil.MAX_RETRIES);
} /**
*
* 描述:构造函数
* @author mao2080@sina.com
* @created 2017年4月20日 下午3:52:53
* @since
* @param businessType 业务类型
* @param baseSleepTimeMs 获取锁-每次尝试间隔(单位:毫秒)
* @param maxRetries 获取锁-最大尝试次数
* @throws BusinessException
*/
public ZKLockUtil(BusinessType businessType, int baseSleepTimeMs, int maxRetries) throws Exception {
this.initService(businessType, baseSleepTimeMs, maxRetries);
} /**
*
* 描述:释放资源
* @author mao2080@sina.com
* @created 2017年4月20日 下午3:58:03
* @since
*/
public void close(){
try {
this.getLock().release();
} catch (Exception e) {
e.printStackTrace();
}
try {
this.client.close();
} catch (Exception e) {
e.printStackTrace();
}
} /**
*
* 描述:判断对象是否为空
* @author mao2080@sina.com
* @created 2017年3月20日 上午11:33:55
* @since
* @param obj
* @return
*/
public static boolean isBlank(Object obj){
if(obj == null || "".equals(obj.toString())){
return true;
}
return false;
} public InterProcessMutex getLock() {
return lock;
} public void setLock(InterProcessMutex lock) {
this.lock = lock;
} /**
*
* 项目名称:---
* 模块名称:公共服务-锁工具
* 功能描述:业务类型
* 创建人: mao2080@sina.com
* 创建时间:2017年4月22日 下午12:27:04
* 修改人: mao2080@sina.com
* 修改时间:2017年4月22日 下午12:27:04
*/
public enum BusinessType { Demo("0001", "Demo"), ; /**业务类型编码 */
private String code; /**业务类型名称 */
private String name; /**
*
* 描述:构建业务类型
* @author mao2080@sina.com
* @created 2017年4月10日 下午3:42:57
* @since
* @param code 业务类型编码
* @param name 业务类型名称
* @return
*/
private BusinessType(String code, String name) {
this.code = code;
this.name = name;
} public String getCode() {
return code;
} public void setCode(String code) {
this.code = code;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public static void main(String[] args) {
System.out.println(BusinessType.Demo.code);
} } }
3、使用场景
package com.mao; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import com.mao.ZKLockUtil.BusinessType; /**
*
* 项目名称:---
* 模块名称:公共服务-锁工具
* 功能描述:锁工具类
* 创建人: mao2080@sina.com
* 创建时间:2017年4月20日下午4:35:56
* 修改人: mao2080@sina.com
* 修改时间:2017年4月20日 下午4:35:56
*/
public class ZKLockUtilTest { /**
*
* 描述:具体使用样例
*
* @author mao2080@sina.com
* @created 2017年4月22日 下午12:29:38
* @since
* @param args
* @throws Exception
*/
public static void main1(String[] args) throws Exception {
ZKLockUtil lock = new ZKLockUtil(BusinessType.Demo);
try {
if (lock.getLock().acquire(40, TimeUnit.SECONDS)) {
System.out.println("get lock success...do work");
Thread.sleep(20000);
}
} catch (Exception e) {
System.out.println("get lock fail...," + e.getMessage());
e.printStackTrace();
} finally {
lock.close();
}
} /**
*
* 描述:启动线程模拟并发访问
*
* @author mao2080@sina.com
* @created 2017年4月22日 下午12:29:13
* @since
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(5);
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
exec.submit(new MyLock("client" + i, latch));
}
exec.shutdown();
latch.await();
System.out.println("所有任务执行完毕");
} static class MyLock implements Runnable { private String name; private CountDownLatch latch; public MyLock(String name, CountDownLatch latch) {
this.name = name;
this.latch = latch;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public void run() {
ZKLockUtil locks = null;
try {
locks = new ZKLockUtil(BusinessType.Demo);
} catch (Exception e1) {
e1.printStackTrace();
return;
}
try {
if (locks.getLock().acquire(40, TimeUnit.SECONDS)) {
System.out.println("----------" + this.name+ "获得资源----------");
System.out.println("----------" + this.name+ "正在处理资源----------");
Thread.sleep(1 * 2000);
System.out.println("----------" + this.name+ "资源使用完毕----------");
latch.countDown();
}
} catch (Exception e) {
System.out.println("get lock fail...," + e.getMessage());
e.printStackTrace();
} finally {
locks.close();
}
}
}
}
4、运行结果
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
----------client1获得资源----------
----------client1正在处理资源----------
----------client1资源使用完毕----------
----------client4获得资源----------
----------client4正在处理资源----------
----------client4资源使用完毕----------
----------client2获得资源----------
----------client2正在处理资源----------
----------client2资源使用完毕----------
----------client0获得资源----------
----------client0正在处理资源----------
----------client0资源使用完毕----------
----------client3获得资源----------
----------client3正在处理资源----------
----------client3资源使用完毕----------
所有任务执行完毕
5、参考博客
1、http://blog.csdn.net/wuzhilon88/article/details/41121195
2、http://www.cnblogs.com/LiZhiW/p/4931577.html
6、本文demo下载
利用Zookeeper实现分布式锁的更多相关文章
- 利用Zookeeper实现分布式锁及服务注册中心
对于Zookeeper的定义以及原理,网上已经有很多的优秀文章对其进行了详细的介绍,所以本文不再进行这方面的阐述. 本文主要介绍一些基本的准备工作以及zookeeper.net的使用. 本文源代码gi ...
- ZooKeeper示例 分布式锁
[转载请注明作者和原文链接, 如有谬误, 欢迎在评论中指正. ] 场景描述 在分布式应用, 往往存在多个进程提供同一服务. 这些进程有可能在相同的机器上, 也有可能分布在不同的机器上. 如果这些进程 ...
- 基于 Zookeeper 的分布式锁实现
1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...
- 利用redis实现分布式锁
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于ZooKeeper的分布式锁: 3. 基于Redis的分布式锁: 这里大概说一下三种方式的优缺点,数据库乐观锁优点是实现简单,只需要for ...
- zookeeper — 实现分布式锁
一.前言 在之前的文章中介绍过分布式锁的特点和利用Redis实现简单的分布式锁.但是分布式锁的实现还有很多其他方式,但是万变不离其宗,始终遵循一个特点:同一时刻只能有一个操作获取.这篇文章主要介绍如何 ...
- ZooKeeper的分布式锁实现
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于Redis的分布式锁: 3. 基于ZooKeeper的分布式锁. 本篇博客将介绍第三种方式,基于Zookeeper实现分布式锁.虽然网上已 ...
- 分布式锁(3) ----- 基于zookeeper的分布式锁
分布式锁系列文章 分布式锁(1) ----- 介绍和基于数据库的分布式锁 分布式锁(2) ----- 基于redis的分布式锁 分布式锁(3) ----- 基于zookeeper的分布式锁 代码:ht ...
- Redis、Zookeeper实现分布式锁——原理与实践
Redis与分布式锁的问题已经是老生常谈了,本文尝试总结一些Redis.Zookeeper实现分布式锁的常用方案,并提供一些比较好的实践思路(基于Java).不足之处,欢迎探讨. Redis分布式锁 ...
- 基于Zookeeper的分布式锁(干干干货)
原文地址: https://juejin.im/post/5df883d96fb9a0163514d97f 介绍 为什么使用锁 锁的出现是为了解决资源争用问题,在单进程环境下的资源争夺可以使用 JDK ...
随机推荐
- js中的奇闻异事
- mybatis字符#与字符$的区别
问题:使用in查询查询出一批数据,in查询的参数是字符串拼接的.调试过程中,把mybatis输出的sql复制到navicat中,在控制台将sql的参数也复制出来,替换到sql的字符 '?' 的位置,执 ...
- 94. Binary Tree Inorder Traversal (Java)
Given a binary tree, return the inorder traversal of its nodes' values. Example: Input: [1,null,2,3] ...
- IDEA修改Maven全局配置
在使用过程中发现,IDEA每次新建一个Project ,这个maven配置都会初始化默认的. 这里需要设置下全局配置: File -> Other Settings -> Settings ...
- EfficientNet学习笔记
EfficientNet是谷歌大脑在2019年提出的,论文地址是:https://arxiv.org/pdf/1905.11946.pdf 这篇文章主要想解决的一个问题是,如何平衡网络的深度.宽度和分 ...
- zencart批量设置热卖商品 best seller、点击最高最受欢迎产品 most popular
zencart批量设置某分类下热卖商品数 best seller ; ,,,,,); zencart批量设置某产品点击最高最受欢迎产品 most popular ; ,,,,,);
- LIS 普及题
题意 给你一个长度为 \(n\) 的序列 \(a\). 问是否存在一个长度为 \(L\) 的上升子序列,即存在 \(\{x_1,x_2,...,x_L\}(x_1\lt x_2\lt ...\lt x ...
- [uboot] (番外篇)global_data介绍(转)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/ooonebook/article/det ...
- 【BZOJ4596】【Luogu P4336】 [SHOI2016]黑暗前的幻想乡 矩阵树定理,容斥
同样是矩阵树定理的裸题.但是要解决它需要能够想到容斥才可以. \(20\)以内的数据范围一定要试试容斥的想法. #include <bits/stdc++.h> using namespa ...
- grunt-contrib-cssmin CSS压缩以及合并
grunt-contrib-cssmin:压缩以及合并CSS文件 安装插件:npm install grunt-contrib-cssmin --save-dev 不设置compatibility与n ...