文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

【大厂面试题】Redis中是如何实现分布式锁的?

2024-12-11 19:48

关注
  1.  数据库乐观锁;
  2.  基于Redis的分布式锁;
  3.  基于ZooKeeper的分布式锁。

本地面试考点是,你对Redis使用熟悉吗?Redis中是如何实现分布式锁的。

要点

Redis要实现分布式锁,以下条件应该得到满足

互斥性

不能死锁

容错性

实现

可以直接通过 set key value px milliseconds nx 命令实现加锁, 通过Lua脚本实现解锁。 

  1. //获取锁(unique_value可以是UUID等)  
  2. SET resource_name unique_value NX PX  30000  
  3. //释放锁(lua脚本中,一定要比较value,防止误解锁)  
  4. if redis.call("get",KEYS[1]) == ARGV[1] then  
  5.     return redis.call("del",KEYS[1]) 
  6.  else  
  7.     return 0  
  8. end 

代码解释

加锁代码分析

首先,set()加入了NX参数,可以保证如果已有key存在,则函数不会调用成功,也就是只有一个客户端能持有锁,满足互斥性。其次,由于我们对锁设置了过期时间,即使锁的持有者后续发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁(即key被删除),不会发生死锁。最后,因为我们将value赋值为requestId,用来标识这把锁是属于哪个请求加的,那么在客户端在解锁的时候就可以进行校验是否是同一个客户端。

解锁代码分析

将Lua代码传到jedis.eval()方法里,并使参数KEYS[1]赋值为lockKey,ARGV[1]赋值为requestId。在执行的时候,首先会获取锁对应的value值,检查是否与requestId相等,如果相等则解锁(删除key)。

存在的风险

如果存储锁对应key的那个节点挂了的话,就可能存在丢失锁的风险,导致出现多个客户端持有锁的情况,这样就不能实现资源的独享了。

  1.  客户端A从master获取到锁
  2.  在master将锁同步到slave之前,master宕掉了(Redis的主从同步通常是异步的)。

    主从切换,slave节点被晋级为master节点

      3.  客户端B取得了同一个资源被客户端A已经获取到的另外一个锁。导致存在同一时刻存不止一个线程获取到锁的情况。

redlock算法出现

这个场景是假设有一个 redis cluster,有 5 个 redis master 实例。然后执行如下步骤获取一把锁:

  1.  获取当前时间戳,单位是毫秒;
  2.  跟上面类似,轮流尝试在每个 master 节点上创建锁,过期时间较短,一般就几十毫秒;
  3.  尝试在大多数节点上建立一个锁,比如 5 个节点就要求是 3 个节点 n / 2 + 1;
  4.  客户端计算建立好锁的时间,如果建立锁的时间小于超时时间,就算建立成功了;
  5.  要是锁建立失败了,那么就依次之前建立过的锁删除;
  6.  只要别人建立了一把分布式锁,你就得不断轮询去尝试获取锁。

Redis 官方给出了以上两种基于 Redis 实现分布式锁的方法,详细说明可以查看:

https://redis.io/topics/distlock

Redisson实现

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还实现了可重入锁(Reentrant Lock)、公平锁(Fair Lock、联锁(MultiLock)、 红锁(RedLock)、 读写锁(ReadWriteLock)等,还提供了许多分布式服务。

Redisson提供了使用Redis的最简单和最便捷的方法。Redisson的宗旨是促进使用者对Redis的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。

Redisson 分布式重入锁用法

Redisson 支持单点模式、主从模式、哨兵模式、集群模式,这里以单点模式为例: 

  1. // 1.构造redisson实现分布式锁必要的Config  
  2. Config config = new Config();  
  3. config.useSingleServer().setAddress("redis://127.0.0.1:5379").setPassword("123456").setDatabase(0);  
  4. // 2.构造RedissonClient  
  5. RedissonClient redissonClient = Redisson.create(config);  
  6. // 3.获取锁对象实例(无法保证是按线程的顺序获取到)  
  7. RLock rLock = redissonClient.getLock(lockKey);  
  8. try {  
  9.      
  10.     boolean res = rLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS);  
  11.     if (res) {  
  12.         //成功获得锁,在这里处理业务  
  13.     }  
  14. } catch (Exception e) {  
  15.     throw new RuntimeException("aquire lock fail");  
  16. }finally{  
  17.     //无论如何, 最后都要解锁  
  18.     rLock.unlock();  

加锁流程图

解锁流程图

我们可以看到,RedissonLock是可重入的,并且考虑了失败重试,可以设置锁的最大等待时间, 在实现上也做了一些优化,减少了无效的锁申请,提升了资源的利用率。

需要特别注意的是,RedissonLock 同样没有解决 节点挂掉的时候,存在丢失锁的风险的问题。而现实情况是有一些场景无法容忍的,所以 Redisson 提供了实现了redlock算法的 RedissonRedLock,RedissonRedLock 真正解决了单点失败的问题,代价是需要额外的为 RedissonRedLock 搭建Redis环境。

所以,如果业务场景可以容忍这种小概率的错误,则推荐使用 RedissonLock, 如果无法容忍,则推荐使用 RedissonRedLock。 

 

来源:民工哥技术之路内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯