数据库
首页 > 数据库> > redis分布式锁

redis分布式锁

作者:互联网

 

1、Redis分布式锁流程图(二个要点:①超时解锁 ②获得锁的线程唯一标识,用以谁的锁谁来解锁)

  

2、Redis分布式锁算法:

  ①加锁

    a:锁的唯一标识(设置随机值作为锁的持有人,只有锁的持有人才可以解锁)

    b:锁的超时时间

      加锁指令:jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime)

      lockKey:key值

      requestID:value值,即锁的唯一标识,只有该requestId才可以解锁对应锁

      set_if_not_exist:当key不存在时进行set操作,如果key存在则不做任何操作

      set_with_expire_time:过期时间key

      expireTime:具体过期时间值(一般是通过压测得到一个经验值)

   ②解锁

    a:检查是否持有锁

    b:持有锁条件下删除锁

    采用Lua脚本进行删锁操作

    

 

3、redis代码:

3.1redis加锁代码

   
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;

    }

}
View Code

  上述代码执行有两个结果:①锁不存在,进行加锁操作   ②存在锁,不做任何操作

  代码中满足三个条件:①requestID唯一锁持有人标识 ,满足谁的锁谁去解锁

            ②expireTime 设置超时时间,如果超时自动解锁

            ③nx 保证key存在则不进行任何操作

 

3.2redis解锁代码  

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;

    }

}
View Code

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

  Lua脚本功能:获取key对应的value,然后和requestID对比是否一样,如果一样则解锁,返回true,如果不相等则返回false

 

 

4、主节点在同步锁到子节点前挂掉处理方案:redLock

                          

 

                   

另外,如果客户端A在master1、2、3获取到锁后,master1宕机,此时客户端B又过来请求锁,在master1、4、5获得锁,这种情况下A、B均获得锁了,解决方案是:master1宕机后不会立马重启,而是延迟重启,在延迟重启的时间段内,保证客户端A便执行完代码

 

标签:return,String,解锁,redis,jedis,requestId,lockKey,分布式
来源: https://www.cnblogs.com/enhance/p/10988536.html