zookeeper-1.3 JAVA分布式锁的实现及watch代码实现封装

zookeeper-4

zookeeper 2和3系列正在画图,就先把代码实现的部分发表出来,后面会补上2-3系列的。如需转载请标注一下备注



一、zk实现分布式锁

zk要实现分布式锁,首先需要了解分布式锁实现的几个问题:
  1. 争抢锁-(只有一个人获得了锁)
  2. 获取锁的那个人出现了问题?
  3. 获取锁的人成功抢到了锁-》锁释放
  4. 锁释放了删除了,别人怎么知道

zk锁和redis锁虽然都是分布式锁,但是本质上是不一样的,例如redis锁的实现的几个问题:

  1. 争抢锁 - (只有一个人抢到了)
  2. 锁没有过期时间,业务挂了,锁还继续?
  3. 设置锁超时时间,时间超时了但业务没执行完?
  4. 设置较长的过期时间,但业务挂了,锁还继续?锁的时间多长合适?

这些都是加锁带来的问题。ZK锁的几个问题在这里会给出讲解,而redis锁的问题在下个系列redis中会讲解出来。

zk锁问题的解决

  1. 获取锁的那个人出现了问题?
    解决:在zk中znode是有几个特点,第一章的时候讲过,znode包含(持久节点,持久序列节点,临时节点,临时序列节点)在这里可以使用znode的临时节点。当加锁的人出现了问题,会断开和zk的链接,(临时节点特点是:当client断开链接后,临时节点消失)临时节点的消失,是不是就意味着锁消失了。
    那么zk锁和redis锁一对比大家是不是就发现,在redis里面你需要对锁设置时间,还需要额外开启安全线程对锁进行监控。例如业务没执行完需要增加锁的超时时间等。成本就上去了。

  2. zk锁释放了,别人怎么知道?三种方案
    (1)主动轮训,心跳 。 弊端:延迟,多台机器对zookeeper压力
    (2)zk的watch来实现,可以解决延迟问题。 弊端:多台机器对zookeeper有压力
    (3)利用序列节点+watch 来实现,watch谁?每个序列节点watch前面一个(这里可以理解为队列,每个队列的后面一个watch前面一个目标),最小的一个获得锁,一旦最小的释放了锁,后面一个就会根据watch来获取锁,这样就不用队列所有都对节点watch。成本:zk只给第二个发事件回调。减少了zookeeper压力

zk分布式锁的代码实现

下面展示一些 代码片。倒入maven中zk的jar

		<dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </dependency>

curator对zk的api做了封装,直接使用curator,初始化

	/**
     * 使用 curator 操作 zookeeper
     * @author niney
     */
    @Bean(name = "curatorFramework")
    public CuratorFramework curatorFramework(ZkProperties zk) throws Exception {
   
            //构建 CuratorFramework
            CuratorFramework curatorFramework =
                    CuratorFrameworkFactory.builder()
                            //连接地址集群用,隔开
                            .connectString(zk.getConnectIps())
                            //连接创建超时时间,单位毫秒
                         .connectionTimeoutMs(zk.getConnectionTimeOutMs())
                            //会话超时时间
                            .sessionTimeoutMs(zk.getSessionTimeOutMs())
                            //配置zookeeper连接的重试策略
                            .retryPolicy(
                                    new ExponentialBackoffRetry(
                                    //每次重试时间间隔,单位毫秒 
                                    //重试次数
                                   zk.getSleepTimeMs(),zk.getMaxRetries()
                                    ))
                            //设置命名空间 在操作节点的时候,会以这个为父节点
                            .namespace("fm-zk")
                            .build();
            curatorFramework.start();
            return curatorFramework;
    }

zk锁实现

 //通过 InterProcessMutex 该类来获取可重入共性锁
 		InterProcessMutex lock = new InterProcessMutex(
    		(CuratorFramework) SpringContext.getBean("curatorFramework"), path
        );
		try {
   
            lock.acquire();
           //这里业务逻辑实现 xxxxx
           //xxxxxxxxxx
        } catch (Exception e) {
   
            throw new ServerRuntimeException(e);
        } finally {
   
            if (lock.isAcquiredInThisProcess()) {
   
                try {
   
                    lock.release();
                } catch (Exception e) {
   
                    throw new 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值