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 相关文章推荐
springboot利用redis、Redisson处理并发问题的操作
Jun 18 Java/Android
Java 语言中Object 类和System 类详解
Jul 07 Java/Android
JPA 通过Specification如何实现复杂查询
Nov 23 Java/Android
java objectUtils 使用可能会出现的问题
Feb 28 Java/Android
使用Java去实现超市会员管理系统
Mar 18 Java/Android
JavaWeb实现显示mysql数据库数据
Mar 19 Java/Android
Java虚拟机内存结构及编码实战分享
Apr 07 Java/Android
一文搞懂Java中的注解和反射
Jun 21 Java/Android
阿里面试Nacos配置中心交互模型是push还是pull原理解析
Jul 23 Java/Android
Java代码规范与质量检测插件SonarLint的使用
Aug 05 Java/Android
Java Spring读取和存储详细操作
Aug 05 Java/Android
Springboot集成kafka高级应用实战分享
Aug 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
PHP读取XML值的代码(推荐)
2011/01/01 PHP
PHP和Mysqlweb应用开发核心技术 第1部分 Php基础-3 代码组织和重用2
2011/07/03 PHP
php curl 上传文件代码实例
2015/04/27 PHP
利用javascript实现一些常用软件的下载导航
2009/08/03 Javascript
jQuery实现列表自动循环滚动鼠标悬停时停止滚动
2013/09/06 Javascript
JavaScript中对象property的删除方法介绍
2014/12/30 Javascript
Javascript字符串拼接小技巧(推荐)
2016/06/02 Javascript
JS获取多维数组中相同键的值实现方法示例
2017/01/06 Javascript
AngularJS全局警告框实现方法示例
2017/05/18 Javascript
浅谈原型对象的常用开发模式
2017/07/22 Javascript
NodeJs通过async/await处理异步的方法
2017/10/09 NodeJs
JS实现的ajax和同源策略(实例讲解)
2017/12/01 Javascript
详解Node.js中的Async和Await函数
2018/02/22 Javascript
微信小程序和百度的语音识别接口详解
2019/05/06 Javascript
Node.js 路由的实现方法
2019/06/05 Javascript
[38:32]DOTA2上海特级锦标赛A组资格赛#2 Secret VS EHOME第二局
2016/02/26 DOTA
浅谈Python中带_的变量或函数命名
2017/12/04 Python
Python中利用aiohttp制作异步爬虫及简单应用
2018/11/29 Python
python之PyQt按钮右键菜单功能的实现代码
2019/08/17 Python
基于python的itchat库实现微信聊天机器人(推荐)
2019/10/29 Python
python实现身份证实名认证的方法实例
2019/11/08 Python
python scrapy重复执行实现代码详解
2019/12/28 Python
python对一个数向上取整的实例方法
2020/06/18 Python
浅谈python出错时traceback的解读
2020/07/15 Python
基于logstash实现日志文件同步elasticsearch
2020/08/06 Python
HTML页面中添加Canvas标签示例
2015/01/01 HTML / CSS
写好自荐信要注意的问题
2013/11/10 职场文书
电子商务毕业生求职信
2013/11/10 职场文书
九年级数学教学反思
2014/02/02 职场文书
党员干部群众路线个人整改措施
2014/09/18 职场文书
医院护士党的群众路线教育实践活动对照检查材料思想汇报
2014/10/04 职场文书
干部作风整顿个人剖析材料
2014/10/06 职场文书
原告离婚代理词
2015/05/23 职场文书
变长双向rnn的正确使用姿势教学
2021/05/31 Python
Oracle11g R2 安装教程完整版
2021/06/04 Oracle
Pandas实现批量拆分与合并Excel的示例代码
2022/05/30 Python