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 相关文章推荐
简单总结SpringMVC拦截器的使用方法
Jun 28 Java/Android
SpringBoot整合Mybatis Generator自动生成代码
Aug 23 Java/Android
Java Spring 控制反转(IOC)容器详解
Oct 05 Java/Android
Java 在生活中的 10 大应用
Nov 02 Java/Android
关于MybatisPlus配置双数据库驱动连接数据库问题
Jan 22 Java/Android
Android Flutter实现图片滑动切换效果
Apr 07 Java/Android
IDEA 2022 Translation 未知错误 翻译文档失败
Apr 24 Java/Android
Android studio 简单计算器的编写
May 20 Java/Android
Java处理延时任务的常用几种解决方案
Jun 01 Java/Android
MyBatis在注解上使用动态SQL方式(@select使用if)
Jul 07 Java/Android
spring boot实现文件上传
Aug 14 Java/Android
Mybatis 一级缓存和二级缓存原理区别
Sep 23 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
[转帖]PHP世纪万年历
2006/12/06 PHP
基于session_unset与session_destroy的区别详解
2013/06/03 PHP
php中apc缓存使用示例
2013/12/25 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(八)
2014/06/23 PHP
PHP中危险的file_put_contents函数详解
2017/11/04 PHP
PHP设计模式之PHP迭代器模式讲解
2019/03/22 PHP
Laravel框架使用技巧之使用url()全局函数返回前一个页面的地址方法详解
2020/04/06 PHP
在IE下:float属性会影响offsetTop的取值
2006/12/22 Javascript
js 动态文字滚动的例子
2011/01/17 Javascript
优化innerHTML操作(提高代码执行效率)
2011/08/20 Javascript
分享20多个很棒的jQuery 文件上传插件或教程
2011/09/04 Javascript
css配合jquery美化 select
2013/11/29 Javascript
jquery.multiselect多选下拉框实现代码
2016/11/11 Javascript
Node.js与Sails redis组件的使用教程
2017/02/14 Javascript
基于jQuery和CSS3实现APPLE TV海报视差效果
2017/06/16 jQuery
基于Vue制作组织架构树组件
2017/12/06 Javascript
js实现二级菜单点击显示当前内容效果
2018/04/28 Javascript
Bootstrap 模态框自定义点击和关闭事件详解
2018/08/10 Javascript
React 无状态组件(Stateless Component) 与高阶组件
2018/08/14 Javascript
JS实现图片拖拽交换效果
2018/11/30 Javascript
详解babel升级到7.X采坑总结
2019/05/12 Javascript
js实现图片区域可点击大小随意改变(适用移动端)代码实例
2019/09/11 Javascript
vuex实现数据状态持久化
2019/11/11 Javascript
JavaScript修改注册表实例代码
2020/01/05 Javascript
JavaScript面试中常考的字符串操作方法大全(包含ES6)
2020/05/10 Javascript
[52:08]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#2Fnatic VS OG第一局
2016/03/05 DOTA
python traceback捕获并打印异常的方法
2018/08/31 Python
对python遍历文件夹中的所有jpg文件的实例详解
2018/12/08 Python
基于numpy中的expand_dims函数用法
2019/12/18 Python
python使用ctypes库调用DLL动态链接库
2020/10/22 Python
Speedo速比涛德国官方网站:世界领先的泳装品牌
2019/08/26 全球购物
介绍一下Mysql的存储引擎
2015/02/12 面试题
行政主管岗位职责范本
2015/04/09 职场文书
高中升旗仪式主持词
2015/07/03 职场文书
如何在向量化NumPy数组上进行移动窗口
2021/05/18 Python
MySQL 那些常见的错误设计规范,你都知道吗
2021/07/16 MySQL