redis 锁的获取与删除,以及加锁解锁不对产生的问题

jedis版本3.2.0

package com.hgf.user.utils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import java.util.Collections;

/**
 * created by hgf
 * created time is 2020/3/22
 */
public class RedisUtils {
    private static final String LOCK_SUCCESS = "OK";
    private static final Long RELEASE_SUCCESS = 1L;
    /**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
        SetParams params = new SetParams();
        params.ex(expireTime);
        params.nx();
        String result = jedis.set(lockKey, requestId,params);

        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
    /**
     * 释放分布式锁
     * @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;

    }

}

1.预防死锁
一个客户端获取锁成功,但是在释放锁之前崩溃了,此时该客户端实际上已经失去了对公共资源的操作权,但却没有办法请求解锁(删除 Key-Value键值对),那么,它就会一直持有这个锁,而其它客户端永远无法获得锁。
解决方法:设置自动过期时间
2.设置锁自动过期时间以预防死锁存在的隐患
客户端 A 获取锁成功;
客户端 A 在某个操作上阻塞了很长时间(对于 Java 而言,如发生 Full-GC);
过期时间到,锁自动释放;
客户端 B 获取到了对应同一个资源的锁;
客户端 A 从阻塞中恢复过来,认为自己依旧持有锁,继续操作同一个资源,导致互斥性失效。
解决方法:拿自己加锁的value与redis中的value做对比,不相同说明不在持有锁,则放弃对资源的操作
3.解锁操作的原子性
客户端 A 获取锁成功;
客户端 A 访问共享资源;
客户端 A 为了释放锁,先执行 GET 操作获取锁对应的随机字符串的值;
客户端 A 判断随机字符串的值,与预期的值相等;
客户端 A 由于某个原因阻塞了很长时间;
过期时间到了,锁自动释放了;
客户端 B 获取到了对应同一个资源的锁;
客户端 A 从阻塞中恢复过来,执行 DEL 操纵,释放掉了客户端 B 持有的锁。
解决方法:使用Lua脚本进行解锁
4.Redis 节点故障后,主备切换的数据一致性
客户端 A 从 Master 获取了锁;
Master 宕机了,存储锁的 Key 还没有来得及同步到 Slave 上;
Slave 升级为 Master;
客户端 B 从新的 Master 获取到了对应同一个资源的锁;
客户端 A 和客户端 B 同时持有了同一个资源的锁,锁的安全性被打破。
解决方法:redlock

参考文章
Redis分布式锁注意事项
redis加锁的几种实现

你可能感兴趣的:(java)