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实现分布式事务的三种方案
Jun 11 Java/Android
Jackson 反序列化时实现大小写不敏感设置
Jun 29 Java/Android
Java并发编程必备之Future机制
Jun 30 Java/Android
Java tomcat手动配置servlet详解
Nov 27 Java/Android
maven依赖的version声明控制方式
Jan 18 Java/Android
java objectUtils 使用可能会出现的问题
Feb 28 Java/Android
spring cloud eureka 服务启动失败的原因分析及解决方法
Mar 17 Java/Android
RestTemplate如何通过HTTP Basic Auth认证示例说明
Mar 17 Java/Android
Java 数据结构七大排序使用分析
Apr 02 Java/Android
Qt数据库应用之实现图片转pdf
Jun 01 Java/Android
详解Spring Bean的配置方式与实例化
Jun 10 Java/Android
Java界面编程实现界面跳转
Jun 16 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的ob_start来生成静态页面的方法分析
2011/03/09 PHP
PHP数组 为文章加关键字连接 文章内容自动加链接
2011/12/29 PHP
PHP手机号码归属地查询代码(API接口/mysql)
2012/09/04 PHP
使用php检测用户当前使用的浏览器是否为IE浏览器
2013/12/03 PHP
php中unserialize返回false的解决方法
2014/09/22 PHP
PHP实现的网站目录扫描索引工具
2016/09/08 PHP
PHP重置数组为连续数字索引的几种方式总结
2018/03/12 PHP
PHP测试框架PHPUnit组织测试操作示例
2018/05/28 PHP
Swoole 5将移除自动添加Event::wait()特性详解
2019/07/10 PHP
javascript实现tabs选项卡切换效果(自写原生js)
2013/03/19 Javascript
javascript的document.referrer浏览器支持、失效情况总结
2014/07/18 Javascript
jQuery实现的导航条切换可显示隐藏
2014/10/22 Javascript
使用jQuery mobile库检测url绝对地址和相对地址的方法
2015/12/04 Javascript
Angular和Vue双向数据绑定的实现原理(重点是vue的双向绑定)
2016/11/22 Javascript
Angularjs 实现移动端在线测评效果(推荐)
2017/04/05 Javascript
JavaScript获取tr td 的三种方式全面总结(推荐)
2017/08/15 Javascript
微信小程序有旋转动画效果的音乐组件实例代码
2018/08/22 Javascript
JavaScript在web自动化测试中的作用示例详解
2019/08/25 Javascript
解决vue组件中click事件失效的问题
2019/11/09 Javascript
js获取图片的base64编码并压缩
2020/12/05 Javascript
[02:34]DOTA2亚洲邀请赛 BG战队出场宣传片
2015/03/09 DOTA
python 实现插入排序算法
2012/06/05 Python
Python装饰器decorator用法实例
2014/11/10 Python
Tensorflow中使用tfrecord方式读取数据的方法
2018/06/19 Python
python如何求解两数的最大公约数
2018/09/27 Python
selenium3+python3环境搭建教程图解
2018/12/07 Python
python 实现一次性在文件中写入多行的方法
2019/01/28 Python
python 一个figure上显示多个图像的实例
2019/07/08 Python
Python学习笔记之迭代器和生成器用法实例详解
2019/08/08 Python
python retrying模块的使用方法详解
2019/09/25 Python
利用python3 的pygame模块实现塔防游戏
2019/12/30 Python
python如何实时获取tcpdump输出
2020/09/16 Python
HTML5中的websocket实现直播功能
2018/05/21 HTML / CSS
JD Sports芬兰:英国领先的运动鞋和运动服饰零售商
2018/11/16 全球购物
ktv好的活动方案
2014/08/15 职场文书
唤醒紫霞仙子,携手再游三界!大话手游X《大话西游》电影合作专属剧情任务
2022/04/03 其他游戏