zoukankan      html  css  js  c++  java
  • 分布式锁

    1、分布式锁的定义

    分布式锁,是控制分布式系统之间同步访问共享资源的一种方式。

    2、分布式锁的实现有哪些?

     1.Memcached分布式锁

    利用Memcached的add命令。此命令是原子性操作,只有在key不存在的情况下,才能add成功,也就意味着线程得到了锁。

    2.Redis分布式锁

    和Memcached的方式类似,利用Redis的setnx命令。此命令同样是原子性操作,只有在key不存在的情况下,才能set成功。(setnx命令并不完善,后续会介绍替代方案)

    3.Zookeeper分布式锁

    利用Zookeeper的顺序临时节点,来实现分布式锁和等待队列。Zookeeper设计的初衷,就是为了实现分布式锁服务的。

    4.Chubby

    Google公司实现的粗粒度分布式锁服务,底层利用了Paxos一致性算法。

    3、如何用Redis实现分布式锁?

    1.通过Maven引入Jedis开源组件,jedis是redis的java客户端

       <!-- redis依赖包 -->
        <dependency>
          <groupId>redis.clients</groupId>
          <artifactId>jedis</artifactId>
          <version>2.9.0</version>
        </dependency>

    2.加锁代码

    public class RedisTool {
    
        private static final String LOCK_SUCCESS = "OK";
        private static final String SET_IF_NOT_EXIST = "NX";
        private static final String SET_WITH_EXPIRE_TIME = "PX";
    
        /**
         * 尝试获取分布式锁
         * @param jedis Redis客户端
         * @param lockKey 锁
         * @param requestId 请求标识
         * @param expireTime 超期时间
         * @return 是否获取成功
         */
        public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
    
            String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
    
            if (LOCK_SUCCESS.equals(result)) {
                return true;
            }
            return false;
        }
    
    }

    这个set()方法一共有五个形参:

    • 第一个为key,我们使用key来当锁,因为key是唯一的。

    • 第二个为value,我们传的是requestId,就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据。requestId可以使用UUID.randomUUID().toString()方法生成。

    • 第三个为nxxx,这个参数我们填的是NX,意思是SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;

    • 第四个为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期的设置,具体时间由第五个参数决定。

    • 第五个为time,与第四个参数相呼应,代表key的过期时间。

    总的来说,执行上面的set()方法就只会导致两种结果:1. 当前没有锁(key不存在),那么就进行加锁操作,并对锁设置个有效期,同时value表示加锁的客户端。2. 已有锁存在,不做任何操作。

    3.解锁代码

    public class RedisTool {
    
        private static final Long RELEASE_SUCCESS = 1L;
    
        /**
         * 释放分布式锁
         * @param jedis Redis客户端
         * @param lockKey 锁
         * @param requestId 请求标识
         * @return 是否释放成功
         */
        public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
    String script
    = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (RELEASE_SUCCESS.equals(result)) { return true; } return false; } }

    第一行代码,我们写了一个简单的Lua脚本代码,首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)。使用Lua语言来实现可确保上述操作是原子性的。

    第二行代码,我们将Lua代码传到jedis.eval()方法里,并使参数KEYS[1]赋值为lockKey,ARGV[1]赋值为requestId。eval()方法是将Lua代码交给Redis服务端执行。

    3、如何用ZooKeeper实现分布式锁?

  • 相关阅读:
    PostgerSQL 回收表空间,查看占用磁盘大小
    为 Docker 添加阿里云的镜像地址
    Docker 常用命令
    CentOS 7 安装 Docker
    kafka-常用脚本2
    Nginx 端口被占用(0.0.0.0:443 failed (98: Address already in use))
    nginx: [error] open() "/var/run/nginx.pid" failed (2: No such file or directory)
    检查Nginx 配置文件出否有问题
    Python2 安装虚拟环境
    记录 | 程序员技术博客平台推荐和选取
  • 原文地址:https://www.cnblogs.com/mcahkf/p/9110567.html
Copyright © 2011-2022 走看看