问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Redis分布式锁导致死锁、锁误删的场景及解决方法

创作时间:
作者:
@小白创作中心

Redis分布式锁导致死锁、锁误删的场景及解决方法

引用
CSDN
1.
https://blog.csdn.net/qq_33204709/article/details/139338591

Redis 天生就可以作为一个分布式系统来使用,所以它实现的锁都是分布式锁。

Redis 可以通过 setnx 命令(set if not exists)命令实现分布式锁,实现方式如下所示:

# 加锁
setnx mylock 1
# 释放锁
del mylock

通过执行结果是否为1,可以判断是否成功获取到锁,如下图所示:

Redis 分布式锁存在什么问题?

Redis 分布式锁存在两个问题:

  1. 死锁问题:如果在加锁之后,未设置过期时间锁忘记释放加锁后还没来得及释放锁就宕机了这3种情况都会导致死锁问题。

  2. 锁误删问题:设置了超时时间,但是线程执行超过过期时间后锁误删问题。

解决死锁问题

  1. 方式一:set 升级

MySQL 中解决死锁问题是通过设置超时时间,Redis 也是如此,但是问题来了,第一步先加锁,然后再设置超时时间,那么就不满足原子性了,那怎么办?

官方在 Redis 2.6.12 版本之后,新增了一个功能,我们可以使用一条命令既执行加锁操作,又设置过期时间,相当于:setnx + expire。如下图所示:

  • 第1条命令加锁成功,并设置 30s 过期时间。
  • 第2条命令跟在第1条命令后,还没有超过 30s,所以加锁失败。
  1. 方式二:setIfAbsent 新方法

setIfAbsent() 是 Redis 专门为分布式锁实现的原子操作,其中封装了获取 key、设置 key、设置过期时间等操作。

RedisUtils 工具类:

@Component
public class RedisUtils {
   
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 原子性操作 加锁
     */
    public boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) {
   
        return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit)  
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号