Redis集群中使用分布式锁所遇到的问题

分布式系统在多线程开发中,经常遇到需要对资源加锁的情况,redis分布式锁是比较常见的一种解决方案。下面对Redis集群中使用分布式锁所遇到的问题给出一些解决方案

问题1

如何避免死锁?
当用户1拿到锁以后,若进程挂了、或因为别的原因,没有机会主动释放锁,会导致已经获得锁的客户端一直占用锁,其他客户端永远无法获取到锁。

解决方案:
为了解决以上死锁问题,最容易想到的方案是:在申请锁时,在Redis中实现时,给锁设置一个过期时间,假设操作共享资源的时间不会超过10s,那么加锁时,给这个key设置10s过期即可。并且Redis 2.6.12之后,Redis扩展了SET命令的参数,可以在SET的同时指定EXPIRE时间,这条操作是原子的,例如以下命令是设置锁的过期时间为10秒。

问题2

Redis分布式锁误删

  1. 持有锁的线程1在锁的内部出现了阻塞,而他的锁超时自动释放(del了),这时其他线程,线程2来尝试获得锁,就拿到了这把锁(setnx了);
  2. 2.然后线程2在持有锁执行过程中,线程1反应过来,继续执行,而线程1执行过程中,走到了删除锁逻辑,此时就会把本应该属于线程2的锁进行删除(把线程2的setnx的值del了)。
    业务流程图

解决方案
一:设置redis分布式锁超时时间t时,使t 大于该锁所在线程的超时时间(线程超时时间一般就是该线程调用的接口超时时间)
二:在每一次释放锁之前,判断当前的锁是否属于自己这个线程,这样就避免了释放别人锁的情况。
核心逻辑:在存入锁时,放入自己线程的标识(可以将线程ID拼接到redis key里),在删除锁时,判断当前这把锁的标识是不是自己存入的,如果是,则进行删除,如果不是,则不进行删除。

问题三

Redis分布式锁原子性问题
由于redis 分布式锁key中的线程id是否属于本线程,删除该key,这两个步骤并不是原子性的:假如在delete key的时候发生了阻塞,而导致超时释放锁,将造成以下后果:
此时线程2获取到了锁,正在嘎嘎执行业务的时候,线程1的del阻塞结束了,但由于在判断句内部,这个锁仍然会被释放(即线程2的锁仍然被认为是线程1的,被释放了),这时候线程3进来,又会发生一样的安全问题。

解决方案:
Lua脚本解决多命令原子性问题

Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性。 lua脚本如下:

– 这里的 KEYS[1] 就是锁的key,这里的ARGV[1] 就是当前线程标示
– 获取锁中的标示,判断是否与当前线程标示一致

if (redis.call(‘GET’, KEYS[1]) == ARGV[1]) then
– 一致,则删除锁
return redis.call(‘DEL’, KEYS[1])
end
– 不一致,则直接返回

对应的java 代码

private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;
    static {
        UNLOCK_SCRIPT = new DefaultRedisScript<>();
        UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));
        UNLOCK_SCRIPT.setResultType(Long.class);
    }
 
public void unlock() {
    // 调用lua脚本
    stringRedisTemplate.execute(
            UNLOCK_SCRIPT,
            Collections.singletonList(KEY_PREFIX + name),
            ID_PREFIX + Thread.currentThread().getId());
}
  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值