基于Redission实现的分布式锁——面试题

1.介绍

在分布式系统中,不同节点可能同时尝试访问共享资源或数据。为了确保数据的一致性和避免竞态条件,需要一种机制来协调对这些资源的访问。分布式锁就是这样一种机制,它可以确保在任何给定时刻,只有一个节点可以持有锁,并且只有持有锁的节点可以执行关键代码块。
Redisson提供的分布式锁不仅具有互斥性、可重入性等基本特性,还支持自动续期、超时设置、公平锁等多种高级功能,使得分布式锁的使用更加灵活和强大。

2.分布式锁实现的关键

抢锁机制

  • 怎么保证同一时间只有 1 个服务器能抢到锁?

3.注意事项

  1. 用完锁要释放
  2. 锁一定要加过期时间
  3. 如果方法执行时间过长,锁提前过期了?问题:
    a. 连锁效应:释放掉别人的锁
    b. 这样还是会存在多个方法同时执行的情况
    解决方案:续期
  4. 释放锁的时候,有可能先判断出是自己的锁,但这时锁过期了,最后还是释放了别人的锁
  5. Redis 如果是集群(而不是只有一个 Redis),分布式锁的数据不同步怎么办?

4.实战

1)引入依赖

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.30.0</version>
</dependency>
<!--    版本仅供参考    -->

2)配置Redission

@Configuration
public class RedissonConfig {

    @Bean
    public RedissonClient redissonClient() {
        // 1. 创建配置
        Config config = new Config();
        String redisAddress = "redis://你的IP地址:你的端口号";
        config.useSingleServer().setAddress(redisAddress).setDatabase(你的数据库);
        // 2. 创建实例
        RedissonClient redisson = Redisson.create(config);
        return redisson;
    }
}

3)Redission实现的通用代码块

场景1:多个线程进来都需要处理,但只能一个一个处理(使用自旋机制处理)

		// 只有一个线程能获取到锁
        RLock lock = redissonClient.getLock("加锁名称");
        try {
            // 自旋:抢到锁并执行
            while (true) {
                if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {
                    // 业务实现
                }
            }
        } catch (InterruptedException e) {
            log.error("doCacheRecommendUser error", e);
        } finally {
            // 只能释放自己的锁
            if (lock.isHeldByCurrentThread()) {
                System.out.println("unLock: " + Thread.currentThread().getId());
                lock.unlock();
            }
        }

场景2:多个线程进来只有一个线程处理即可,拿到锁的线程处理,没拿到锁的线程都不处理

		// 只有一个线程能获取到锁
        RLock lock = redissonClient.getLock("加锁名称");
        try {
            // 抢到锁并执行
            if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {
                // 业务实现
            }
            return;
        } catch (InterruptedException e) {
            log.error("doCacheRecommendUser error", e);
        } finally {
            // 只能释放自己的锁
            if (lock.isHeldByCurrentThread()) {
                System.out.println("unLock: " + Thread.currentThread().getId());
                lock.unlock();
            }
        }

5.锁逾期带来的问题

多个线程进来,都需要处理,第一个线程处理的时间是大于上锁的时间,如果不续期,第一个线程还在处理,后续的线程拿到锁也进行处理,会引发线上问题,比如:数据不一致

6.锁逾期的解决方案

  1. 设置合理的过期时间

根据业务场景和实际需求,为分布式锁设置合理的过期时间。过短的过期时间可能导致锁被提前释放,而过长的过期时间则可能导致资源浪费和潜在的死锁问题。
难度较大,需要合理的调研线上处理的时间

  1. 实现自动续期机制

在分布式锁的实现中,可以加入自动续期机制。当锁即将过期时,自动延长其过期时间,以确保在任务完成前锁不会被释放。例如,Redisson等分布式锁框架就提供了自动续期功能。

7.面试回答

提问:你使用Redission分布式锁是怎么实现的?
答:
从介绍场景、实现、可能引发的问题三个方面来回答
介绍场景:1.有一个定时任务的系统,这个时候采用了分布式来部署,定时任务需要从缓存同步到数据库中,这个时候定时任务需要加锁,只能一个服务器来处理即可(任务调度,防止重复操作)。2.在一个系统中有一个功能是会更新数据的,多个线程进来可能引发数据不一致的问题。例如:商品超卖问题(保证数据一致性)。
实现:1.在分布式的定时任务只需要一个服务器进行处理,此时则需要一个服务器获得锁即可,其他服务器没拿到锁则什么都不做。2.商品超卖问题,多个线程进来只有一个线程能拿到锁,其他线程则自旋等待,在拿到锁的那个线程操作完后,其他线程才能拿到锁,拿到锁之后还需要判断商品还有没有库存,有则购买,没有则提示用户。
可能引发的问题:1.锁过期了还没处理完(解决方案:给锁续期);2.自旋引发CPU飙高(解决方案;不用自旋去解决,采用线程唤醒的方式) 等等

以上只是个人理解,仅供参考!!!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值