【445期】面试官:Redis 分布式锁存在什么问题 ?如何解决 ?

1. 如何实现分布式锁

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

【445期】面试官:Redis 分布式锁存在什么问题 ?如何解决 ?

Redis 可以通过 setnx(set if not exists)命令实现分布式锁~

  • setnx mylock true  –  加锁
  • del mylock  –  释放锁
【445期】面试官:Redis 分布式锁存在什么问题 ?如何解决 ?

通过执行结果是否为 1 可以判断是否成功获取到锁~

2. Redis 分布式锁存在什么问题

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

  1. 死锁问题:未设置过期时间,锁忘记释放,加锁后还没来的及释放锁就宕机了都会导致死锁问题.

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

2.1 解决死锁问题

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

官方在 Redis 2.6.12 版本之后,新增了一个功能,我们可以使用一条命令既执行加锁操作,又设置超时时间:setnx 和 expire

【445期】面试官:Redis 分布式锁存在什么问题 ?如何解决 ?

第一条命令成功加锁,并设置 30 s 过期时间

第二条命令跟在第一条命令后,还没有超过 30s,所以获取失败

2.2 解决锁误删问题

锁误删问题是解决死锁问题带来的问题,如何理解 ?

【445期】面试官:Redis 分布式锁存在什么问题 ?如何解决 ?

既然知道了什么是锁误删问题,那么如何解决 ?

答:可以通过添加锁标识来解决.

前面我们使用 set 命令的时候,只使用到了 key,那么可以给 value 设置一个标识,表示当前锁归属于那个线程,例如 value=thread1,value=thread2…..

但是这样解决依然存在问题,因为新增锁标识之后,线程在释放锁的时候,需要执行两步操作了:

  • 判断锁是否属于自己
  • 如果是,就删除锁

这样就不能保证原子性了,那该怎么办?

解决方案

  • 使用 lua 脚本来解决 (Redis 本身就能保证 lua 脚本里面所有命令都是原子性操作)
  • 使用 Redisson 框架来解决(主流)

那么 Redisson 如何实现分布式锁呢 ?

代码示例

1.引入 Redisson 依赖

<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.23.2</version>
</dependency>

2.创建 RedissonClient 对象

@Configuration
public class RedissonConfig {
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        // 如果有密码需要设置密码
        return Redisson.create(config);
    }
}

3.调用分布式锁

@RestController
public class LockController {
    @Resource
    private RedissonClient redissonClient;
 
    @RequestMapping("/lock")
    public String lockResource() throws InterruptedException {
        String lockKey = "myLock";
        // 获取锁
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 超时时间 10s, [tryLock 获取成功才需要释放锁,获取失败不需要释放锁]
            boolean isLocked = lock.tryLock(20, TimeUnit.SECONDS);
            if(isLocked) {
                // 成功获取到锁
                try {
                    TimeUnit.SECONDS.sleep(5);
                    return "成功获取到锁,并执行业务代码";
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            } else {
                // 获取锁失败
                return "获取锁失败";
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "获取锁成功";
    }
}

启动项目,使用 8080 端口访问接口:

【445期】面试官:Redis 分布式锁存在什么问题 ?如何解决 ?

来源:blog.csdn.net/xaiobit_hl/

article/details/132412247


后端专属技术群

构建高质量的技术交流社群,欢迎从事编程开发、技术招聘HR进群,也欢迎大家分享自己公司的内推信息,相互帮助,一起进步!

文明发言,以交流技术职位内推行业探讨为主

广告人士勿入,切勿轻信私聊,防止被骗

【445期】面试官:Redis 分布式锁存在什么问题 ?如何解决 ?

加我好友,拉你进群 

原文始发于微信公众号(Java面试题精选):【445期】面试官:Redis 分布式锁存在什么问题 ?如何解决 ?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/163520.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!