利用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 ...
随机推荐
- node-images Windows 64-bit with Unsupported runtime 错误解决办法 及 node 历史版本下载
在做项目的时候下载的最新的10.16[2019.6.12]版本,出现了模块不兼容的问题[node-images]. 在git上发现了相同问题 https://github.com/zhangyuanw ...
- 18 Python之初识面向对象
1. 类与对象 class Car: #类名首字母大写,严格遵守驼峰命名规范 pass #造车 c = Car() #类名() #创建对象 ##出场之后进行改装 c.color = "红色& ...
- js 条件方法、数组方法
经常写代码写的很多很累赘,看看下面例子,争取以后代码简洁简化.个人也觉得简洁分明的代码很重要. 本文来自另一篇博客:https://www.cnblogs.com/ljx20180807/p/1084 ...
- Java程序员常用的Linux命令01——linux命令基础
1.显示日期的命令date 显示日期: [root@localhost ~]# date 显示年月日: [root@localhost ~]# date '+%Y%m%d' 2.显示日历指令cal 显 ...
- Linux grep命令 -- 三剑客老三
常用选项 -E :开启扩展(Extend)的正则表达式. -i :忽略大小写(ignore case). -v :反过来(invert),只打印没有匹配的,而匹配的反而不打印. -n :显示行号 -w ...
- Woobuntu
Wooyun + Ubuntu = Woobuntu Woobuntu是基于Ubuntu系统的一款安全研究环境配置工具,可以自动安装并配置众多的安全工具与依赖环境,此外还针对中国用户的习惯进行了一些优 ...
- kubesphere集群搭建(多节点)
kubesphere官网:https://kubesphere.io/docs/advanced-v2.0/zh-CN/introduction/intro/ 一.准备环境 1.准备服务器 maste ...
- pamamiko的学习笔记
pamamiko的学习笔记 Paramiko包含两个核心组件,一个为SSHClient类,另一个为SFTPClient类, 一,paramiko的连接有两种方式,一种是通过paramiko.SSHCl ...
- MSSQL日期分组排序
等于今天日期的排上面,大于今天的排中间,小于今天的排下面,带分页.
- 【转载】C++ 11中的右值引用
本篇随笔为转载,原博地址如下:http://www.cnblogs.com/TianFang/archive/2013/01/26/2878356.html 右值引用的功能 首先,我并不介绍什么是右值 ...