后端工程师的高阶面经
邓明
前 Shopee 高级工程师,Beego PMC
6888 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 50 讲
后端工程师的高阶面经
15
15
1.0x
00:00/00:00
登录|注册

37|分布式锁:如何保证Redis分布式锁的高可用和高性能?

你好,我是大明。今天我们来学习一个面试中热度极高的话题——分布式锁。
分布式锁和分布式事务,可以说是分布式系统里面两个又热又难的话题。从理论上来说,分布式锁和分布式事务都涉及到了很多分布式系统里面的基本概念,所以我们不愁找不到切入点。从实践上来说,分布式锁和分布式事务都是属于一不小心就会出错的技术手段。
在面试分布式锁的过程中,我发现大部分人只知道很基础的几个点,比如说只能回答出使用 SETNX 命令,又或者能答出要设置超时时间。当进一步追问的时候,就不知道了。
那么今天我就带你全方位学习分布式锁的知识点,确保你在这个话题之下能够赢得竞争优势。

能用于实现分布式锁的中间件

这一节课的主题是用 Redis 来实现一个分布式锁,但是并不意味着分布式锁只能使用 Redis 来实现。
简单来说,支持排他性操作的中间件都可以作为实现分布式锁的中间件,例如 ZooKeeper、Nacos 等,甚至关系型数据库也可以,比如说利用 MySQL 的 SELECT FOR UPDATE 语法是可以实现分布式锁的。

面试准备

你在公司里面要收集一些信息。
你们公司有没有使用分布式锁的场景?不用分布式锁行不行?
你们使用的分布式锁是怎么实现的?性能怎么样?
你使用的分布式锁有没有做什么性能优化?
你使用的分布式锁是如何加锁、释放锁的?有没有续约机制?
在使用分布式锁的时候,各个环节收到超时响应,你会怎么办?
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

分布式锁是分布式系统中的重要话题,本文深入介绍了如何使用Redis实现高可用和高性能的分布式锁。文章首先介绍了分布式锁的基本概念和在面试中的热度,然后详细讨论了使用Redis的SETNX命令实现加锁和DEL命令实现释放锁的过程,以及加锁失败时的等待时间、实现等待机制和加锁重试的方法。此外,文章还提到了分布式锁需要设置合适的过期时间,并介绍了续约机制和中断业务的处理方法。另外,文章还提到了Redlock算法以及性能优化的方案。总的来说,本文对分布式锁的实现原理和相关技术细节进行了深入浅出的介绍,对于想要深入了解分布式锁的读者具有很高的参考价值。 文章还提到了性能优化的思路,包括优化Redis性能和减少分布式锁的竞争,以及去除分布式锁的场景和思路。此外,还提出了面试思路总结和思考题,为读者提供了更多的思考和讨论空间。 总的来说,本文内容丰富,涵盖了分布式锁的实现原理、性能优化、去除分布式锁的场景和思路等多个方面,对于想要深入了解分布式锁的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端工程师的高阶面经》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(6)

  • 最新
  • 精选
  • Geek_84f004
    老师您好,Singleflight模式多次提到了,但如何实现这个模式,老师有比较好的建议吗?比较害怕的是在这个模式下可能有太多的线程处于等待状态?是否有隐患

    作者回复: 在 GO 里面自带了,JAVA 里面也有开源的实现,其它语言就不清楚了。不过总的来说,还是一个比较复杂的事情,对并发要求比较高。 有隐患,隐患就是你真的去执行的线程执行了很长时间。所以你可以考虑一个结合了超时机制的 singleflight(大部分开源实现不支持)。而别的线程等待超时了,也有两个选择:1. 不再等,直接返回;2. 自己直接去取。 目前我倒是还没遇到过线上因为 singleflight 导致线程长时间阻塞的问题。 归根结底,还是得确保业务要能短时间结束。

    2023-09-13归属地:浙江
    1
  • 冲冲冲
    redLock 加锁多数原则 ,5台机器为啥加锁4个成功,有一个超时失败要把其他四个解锁尼,不是已经超过半数了吗

    作者回复: 我后面释放锁的那里,是指执行业务之后,释放锁的时候不要忘了释放这个超时的节点上的锁。

    2023-10-23归属地:江苏
  • 文敦复
    Singleflight 模式 来优化竞争,感觉需要处理很多复杂问题:选择哪个线程去竞争?获取锁过程中,如果这个线程奔溃,如何通知其他线程?获取锁过程中,其他线程如何自处(直接失败?等待失败? 等待成为竞争者?) 感觉不玩这个奇技淫巧,大开大合,以力破巧更实在,要不然被面试官绕进去,那就尴尬啦...

    作者回复: 哈哈哈,这个在 Go 里面倒是不需要我们烦恼,因为 Go 自身就提供了一个 singleflight。 我个人觉得线程崩溃倒是不太需要考虑,一般来说线程崩溃,都是整个应用崩溃了。就 singleflght 的“标准实现”来说,其他线程都是等待。而使用者可以决定在等待之后,要不要继续尝试新一轮。

    2023-10-11归属地:四川
  • 文敦复
    请教下:“如果 key1 存在,检查值是不是 value1。如果是 value1,那么说明我上一次加锁成功了。考虑到距离重试的时候已经过去了一段时间,所以需要重置一下过期时间。” 如果 key1 都存在了,不就代表上资源被占用了吗,这次加锁应该算失败吧,还继续操作干嘛?

    作者回复: 因为 key1 的值是 value1,也就是你当时加锁成功了(value1是你生成的,且是唯一的,比如说是 uuid),只不过你很不幸拿到了超时响应。

    2023-10-11归属地:四川
  • peter
    请教老师几个问题: Q1:线程1设置key1=value1,线程2设置key1=value2能成功吗? 键相同,都是key1,但值不同,可以设置吗? Q2:订阅键值对,是Redis已经具备的功能吗?还是需要进一步开发? Q3:释放锁的时候,线程1为什么能把线程2的锁释放掉?两个锁应该是不同的锁啊。 Q4:释放锁的时候,比较value,是谁比较?Redis比较吗?

    作者回复: 1. 如果你不用 NX 命令的话,是可以成功的 2. 已经有了,你可以了解一下 Redis 的订阅功能 3. 对同一个 key 加的分布式锁 4. 就是和 redis 里面存储的值比较

    2023-09-13归属地:北京
  • sheep
    课后问题: 1. 重试时候,要考虑重试次数还有重试间隔 2. 有一个分布式锁无效的情况,就是异地部署情况下,两个服务使用的都是自己的redis,这时候使用redis分布式锁无效(因为两个服务没有连到同一个redis中间件么), 但存在只允许一个服务进行执行指定业务的场景。这里有两个服务,B服务(备用业务服)连的数据库是作为A服务(主业务服)连的数据库的备用数据库,数据库MySQL主备数据之间是有进行同步。因此这里做了一个比较简易的方案,就是A服务和B服务定时执行一个业务时,A服务往一个业务执行表(tbl_lock_record)插入一条数据,B服务要执行时,延迟1~2s(考虑到主备数据库延时问题),然后先判断tbl_lock_record表内指定时间范围有没有执行过的数据( 当前时间-定时时长-延迟时长< time <= 当前时间),若有则B服务不进行执行定时任务。 同样,这种方法也存在挺多问题: (1)时间判断不准确情况下,可能两个服务都会执行 (2)若主备数据同步失败(例如延迟时长内数据还未同步),B服务也会进行执行
    2024-02-19归属地:广东
收起评论
显示
设置
留言
6
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部