springboot+zookeeper实现分布式锁


Posted in Java/Android onMarch 21, 2022

springboot+zookeeper实现分布式锁

InterProcessMutex内部实现了zookeeper分布式锁的机制,所以接下来我们尝试使用这个工具来为我们的业务加上分布式锁处理的功能

zookeeper分布式锁的特点:1、分布式 2、公平锁 3、可重入

依赖

<dependency>
   <groupId>org.apache.zookeeper</groupId>
   <artifactId>zookeeper</artifactId>
   <version>3.4.10</version>
</dependency>
<!-- zookeeper 客户端 -->
<dependency>
   <groupId>org.apache.curator</groupId>
   <artifactId>curator-framework</artifactId>
   <version>2.12.0</version>
</dependency>
<dependency>
   <groupId>org.apache.curator</groupId>
   <artifactId>curator-recipes</artifactId>
   <version>2.12.0</version>
</dependency>
<!-- lombok -->
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>1.18.16</version>
   <scope>provided</scope>
</dependency>

本地封装

这个工具类主要封装CuratorFramework这个client(连接Zookeeper)

@Slf4j
public class CuratorClientUtil {
    private String zookeeperServer;

    @Getter
    private CuratorFramework client;

    public CuratorClientUtil(String zookeeperServer) {
        this.zookeeperServer = zookeeperServer;
    }

  	// 创建CuratorFrameworkFactory并且启动
    public void init() {
       // 重试策略,等待1s,最大重试3次
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
        this.client = CuratorFrameworkFactory.builder()
                .connectString(zookeeperServer)
                .sessionTimeoutMs(5000)
                .connectionTimeoutMs(5000)
                .retryPolicy(retryPolicy)
                .build();
        this.client.start();
    }

   // 容器关闭,CuratorFrameworkFactory关闭
    public void destroy() {
        try {
            if (Objects.nonNull(getClient())) {
                getClient().close();
            }
        } catch (Exception e) {
            log.info("CuratorFramework close error=>{}", e.getMessage());
        }
    }
}

配置

@Configuration
public class CuratorConfigration {
    @Value("${zookeeper.server}")
    private String zookeeperServer;
    // 注入时,指定initMethod和destroyMethod
    @Bean(initMethod = "init", destroyMethod = "destroy")
    public CuratorClientUtil curatorClientUtil() {
        CuratorClientUtil clientUtil = new CuratorClientUtil(zookeeperServer);
        return clientUtil;
    }
}

测试代码

模拟不同客户端的请求

@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
    // 注入client工具类
    @Autowired
    private CuratorClientUtil curatorClientUtil;
    // 在zookeeper的/rootLock节点下创建锁对应的临时有序节点
    private String rootLock = "/rootLock";

    @GetMapping("/testLock")
    public Object testLock() throws Exception {
        // 获取当前线程的名字,方便观察那些线程在获取锁
        String threadName = Thread.currentThread().getName();
        InterProcessMutex mutex = new InterProcessMutex(curatorClientUtil.getClient(), rootLock);
        try {
            log.info("{}---获取锁start", threadName);
            // 尝试获取锁,最长等待3s,超时放弃获取
            boolean lockFlag = mutex.acquire(3000, TimeUnit.SECONDS);
            // 获取锁成功,进行业务处理
            if (lockFlag) {
                log.info("{}---获取锁success", threadName);
                // 模拟业务处理,时间为3s
                Thread.sleep(3000);
            } else {
                log.info("{}---获取锁fail", threadName);
            }
        } catch (Exception e) {
            log.info("{}---获取锁异常", threadName);
        } finally {
            // 业务处理完成,释放锁,唤醒比当前线程创建的节点序号大(最靠近)的线程获取锁
            mutex.release();
            log.info("{}---锁release", threadName);
        }
        return "线程:" + threadName + "执行完成";
    }
}

JMeter测试

我们使用JMeter模拟100个客户端同时并发的访问 localhost:8081/test/testLock,相当于100个客户端争抢分布式锁,结果如图右上角所示,100个请求花了5分6s,每个线程获取到锁后业务处理3s,100个线程理想时间为300s(Thread.sleep(3000)),所以运行时间符合。
springboot+zookeeper实现分布式锁springboot+zookeeper实现分布式锁

zookeeper每个线程在/rooLock节点下创建的临时有序节点如下图,由于是临时的,所以线程释放锁后这些节点也会删除
springboot+zookeeper实现分布式锁
100个线程程序日志打印
springboot+zookeeper实现分布式锁

关于InterProcessMutex内部如何实现zookeeper分布式锁,请看我写的这篇文章:在这里

Java/Android 相关文章推荐
Java 将PPT幻灯片转为HTML文件的实现思路
Jun 11 Java/Android
浅析NIO系列之TCP
Jun 15 Java/Android
Mybatis-plus在项目中的简单应用
Jul 01 Java/Android
Java数据开发辅助工具Docker与普通程序使用方法
Sep 15 Java/Android
Java8中Stream的一些神操作
Nov 02 Java/Android
关于Spring配置文件加载方式变化引发的异常详解
Jan 18 Java/Android
Java实现给Word文件添加文字水印
Feb 15 Java/Android
Java 数据结构七大排序使用分析
Apr 02 Java/Android
Java 通过手写分布式雪花SnowFlake生成ID方法详解
Apr 07 Java/Android
Java 轮询锁使用时遇到问题
May 11 Java/Android
Android Canvas绘制文字横纵向对齐
Jun 05 Java/Android
详解Flutter自定义应用程序内键盘的实现方法
Jun 14 Java/Android
Mybatis-Plus进阶分页与乐观锁插件及通用枚举和多数据源详解
Mar 21 #Java/Android
Spring this调用当前类方法无法拦截的示例代码
SpringCloud Feign请求头删除修改的操作代码
Mar 20 #Java/Android
JavaWeb实现显示mysql数据库数据
关于Mybatis中SQL节点的深入解析
springboot 自定义配置 解决Boolean属性不生效
Mar 18 #Java/Android
使用Java去实现超市会员管理系统
Mar 18 #Java/Android
You might like
JS对img进行操作(换图片/切图/轮换/停止)
2013/04/17 Javascript
js离开或刷新页面检测(且兼容FF,IE,Chrome)
2014/03/05 Javascript
写出高效jquery代码的19条指南
2014/03/19 Javascript
JavaScript及jquey实现多个数组的合并操作
2014/09/06 Javascript
JavaScript控制按钮可用或不可用的方法
2015/04/03 Javascript
js实现简单锁屏功能实例
2015/05/27 Javascript
深入php面向对象、模式与实践
2016/02/16 Javascript
原生js制作日历控件实例分享
2016/04/06 Javascript
Bootstrap中文本框的宽度变窄并且加入一副验证码图片的实现方法
2016/06/23 Javascript
轻松实现js弹框显示选项
2016/09/13 Javascript
JS Canvas定时器模拟动态加载动画
2016/09/17 Javascript
JS实现快速比较两个字符串中包含有相同数字的方法
2017/09/11 Javascript
vue学习笔记之v-if和v-show的区别
2017/09/20 Javascript
详解Vue 事件修饰符capture 的使用
2017/12/29 Javascript
node脚手架搭建服务器实现token验证的方法
2021/01/20 Javascript
在Django的模型和公用函数中使用惰性翻译对象
2015/07/27 Python
Python生成短uuid的方法实例详解
2018/05/29 Python
Django添加KindEditor富文本编辑器的使用
2018/10/24 Python
Python 实现微信防撤回功能
2019/04/29 Python
Python3 xml.etree.ElementTree支持的XPath语法详解
2020/03/06 Python
Python通过socketserver处理多个链接
2020/03/18 Python
使用python实现下载我们想听的歌曲,速度超快
2020/07/09 Python
Python 开发工具通过 agent 代理使用的方法
2020/09/27 Python
CSS3实现的渐变幻灯片效果
2020/12/07 HTML / CSS
加拿大国民体育购物网站:National Sports
2018/11/04 全球购物
The North Face北面法国官网:美国著名户外品牌
2019/11/01 全球购物
如何手工释放资源
2013/12/15 面试题
DELPHI面试题研发笔试试卷
2015/11/08 面试题
我的大学生活职业生涯规划
2014/01/02 职场文书
给客户的道歉信
2014/01/13 职场文书
2014年消防工作实施方案
2014/02/20 职场文书
学生实习证明模板汇总
2014/09/25 职场文书
摩登时代观后感
2015/06/03 职场文书
少年犯观后感
2015/06/11 职场文书
毕业赠语大全
2015/06/23 职场文书
eval(cmd)与eval($cmd)的区别与联系
2021/07/07 PHP