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 相关文章推荐
Feign调用全局异常处理解决方案
Jun 24 Java/Android
详解Java线程池是如何重复利用空闲线程的
Jun 26 Java/Android
深入理解java.lang.String类的不可变性
Jun 27 Java/Android
Java基础之详解HashSet的使用方法
Jun 30 Java/Android
Java获取e.printStackTrace()打印的信息方式
Aug 07 Java/Android
使用logback实现按自己的需求打印日志到自定义的文件里
Aug 30 Java/Android
Java使用Unsafe类的示例详解
Sep 25 Java/Android
SpringBoot+Redis实现布隆过滤器的示例代码
Mar 17 Java/Android
SpringBoot2零基础到精通之数据与页面响应
Mar 22 Java/Android
Java 超详细讲解ThreadLocal类的使用
Apr 07 Java/Android
Java 多线程协作作业之信号同步
May 11 Java/Android
MyBatis在注解上使用动态SQL方式(@select使用if)
Jul 07 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
总集篇&特番节目先行播出!《SAO Alicization War of Underworld》第2季度TV动画4月25日放送!
2020/03/06 日漫
我的论坛源代码(七)
2006/10/09 PHP
支付宝接口开发集成支付环境小结
2015/03/17 PHP
详解Laravel视图间共享数据与视图Composer
2016/08/04 PHP
TP5框架使用QueryList采集框架爬小说操作示例
2020/03/26 PHP
javascript div 弹出可拖动窗口
2009/02/26 Javascript
W3C Group的JavaScript1.8 新特性介绍
2009/05/19 Javascript
JS 获取滚动条高度示例代码
2013/10/24 Javascript
JavaScript代码简单实现求杨辉三角给定行的最大值
2013/10/29 Javascript
一个js导致的jquery失效问题的解决方法
2013/11/27 Javascript
现代 JavaScript 开发编程风格Idiomatic.js指南中文版
2014/05/28 Javascript
深入理解javascript构造函数和原型对象
2014/09/23 Javascript
使用jquery菜单插件HoverTree仿京东无限级菜单
2014/12/18 Javascript
JS使用ajax方法获取指定url的head信息中指定字段值的方法
2015/03/24 Javascript
Highcharts使用简例及异步动态读取数据
2015/12/30 Javascript
js前端实现多图图片上传预览的两个方法(推荐)
2016/11/18 Javascript
prototype与__proto__区别详细介绍
2017/01/09 Javascript
js实现文字跑马灯效果
2017/02/23 Javascript
完美实现js选项卡切换效果(二)
2017/03/08 Javascript
redux中间件之redux-thunk的具体使用
2018/04/17 Javascript
基于Node的Axure文件在线预览的实现代码
2019/08/28 Javascript
[04:46]2018年度玩家喜爱的电竞媒体-完美盛典
2018/12/16 DOTA
Python定时器实例代码
2017/11/01 Python
Python入门之三角函数tan()函数实例详解
2017/11/08 Python
一篇文章读懂Python赋值与拷贝
2018/04/19 Python
在Python中使用Neo4j的方法
2019/03/14 Python
基于Numpy.convolve使用Python实现滑动平均滤波的思路详解
2019/05/16 Python
Python人工智能之路 之PyAudio 实现录音 自动化交互实现问答
2019/08/13 Python
利用Python代码实现一键抠背景功能
2019/12/29 Python
python目标检测给图画框,bbox画到图上并保存案例
2020/03/10 Python
实例讲解CSS3中Transform的perspective属性的用法
2016/04/22 HTML / CSS
为中国消费者甄选天下优品:网易严选
2016/08/11 全球购物
初中毕业典礼演讲稿
2014/09/09 职场文书
2014年后勤工作总结
2014/11/18 职场文书
2014-2015学年工作总结
2014/11/27 职场文书
Windows和Linux上部署Golang并运行程序
2022/04/22 Servers