(求锤得锤的故事)Redis锁从面试连环炮聊到神仙打架。 (1)

简介: (求锤得锤的故事)Redis锁从面试连环炮聊到神仙打架。 (1)

又到了一周一次的分享时间啦,老规矩,还是先荒腔走板的聊聊生活。


有上面的图是读大学的时候,一次自行车骑行途中队友抓拍的我的照片。拍照的地方,名字叫做牛背山,一个名字很 low,实际很美的地方。


那条上山的路很难骑,超级烂路和极度变态的陡坡。真是一种折磨,是对意志力的完全考验。


在我们几近崩溃,弹尽粮绝,离山顶还有近两个多小时的时候,一个卡车司机主动要求把我们免费带到山顶。我们拒绝了。


因为同行的星哥他说了一句话:“骑行牛背山这件事情,我这辈子只会做这一次。现在的情况还不是那么糟,如果我搭车上去了,之后想起来我会有遗憾的。所以我更情愿推车。”


第二天下午山上下了一场暴风雪。于是我们几个南方孩子在这少见的雪景中肆意打闹。打雪仗,堆雪人,滑雪......


晚上雪停了之后,我看到了让我终身难忘的场景。星空,美丽到让人想哭的星空!


后来,在人生路上的很多场景中,我都会想起星哥的那句话:这件事,我这辈子只会做这一次,我不想留下遗憾。还会想起那晚璀璨的、触手可及般的星空。


坚持不住的时候再坚持一下,确实是一种难能可贵的精神。


好了,说回文章。


背景铺垫


面试的时候,不管你的简历写没写 Redis,它基本上是一个绕不过的话题。


为了引出本文要讨论的关于 Redlock 的神仙打架的问题,我们就得先通过一个面试连环炮:


1.Redis 做分布式锁的时候有需要注意的问题?


2.如果是 Redis 是单点部署的,会带来什么问题?


3.那你准备怎么解决单点问题呢?


4.集群模式下,比如主从模式,有没有什么问题呢?


5.你知道 Redis 是怎么解决集群模式也不靠谱的问题的吗?


6.那你简单的介绍一下 Redlock 吧?


7.你觉得 Redlock 有什么问题呢?


很明显,上面是一个常规的面试连环套路题。中间还可以插入很多其他的 Redis 的考察点,我这里就不做扩展了。


单点的 Redis 做分布式锁不靠谱,导致了基于 Redis 集群模式的分布式锁解决方案的出现。


基于 Redis 集群模式的分布式锁解决方案还是不靠谱,Redis 的作者提出了 Redlock 的解决方案。


Redis 作者提出的 Redlock 的解决方案,另一位分布式系统的大神觉得它不靠谱,于是他们之间开始了 battle。


基于这场 battle,又引发了更多的讨论。


这场 battle 难分伯仲,没有最后的赢家。如果一定要选出谁是最大的赢家的话,那一定是吃瓜网友。因为对于吃瓜网友来说(比如我),可以从两位大神的交锋中学习到很多东西。


让你深刻的体会到:看起来那么无懈可击的想法,细细推敲之下,并不是那么天衣无缝。


所以本文就按照下面的五个模块展开讲述。


先来一波劝退:本文近1.2w字,谨慎观看。看不下去不要紧,点个赞就是对于我最大的鼓励。奥利给!


单点Redis


按照我的经验,当面试聊到 Redis 的时候,百分之 90 的朋友都会说**:Redis在我们的项目中是用来做热点数据缓存的**。


然后百分之百的面试官都会问:


Redis除了拿来做缓存,你还见过基于Redis的什么用法?


接下来百分之 80 的朋友都会说到:我们还用 Redis 做过分布式锁。


(当然, Redis 除了缓存、分布式锁之外还有非常非常多的奇技淫巧,不是本文重点,大家有兴趣的可以自己去了解一下。)


那么面试官就会接着说:


那你给我描述(或者写一下伪代码)基于Redis的加锁和释放锁的细节吧。


注意面试官这里说的是加锁和释放锁的细节,魔鬼都在细节里。


问这个问题面试官无非是想要听到下面几个关键点:


关键点一:原子命令加锁。因为有的“年久失修”的文章中对于 Redis 的加锁操作是先set key,再设置 key 的过期时间。这样写的根本原因是在早期的 Redis 版本中并不支持原子命令加锁的操作。不是原子操作会带来什么问题,就不用我说了吧?如果你不知道,你先回去等通知吧。


而在 2.6.12 版本后,可以通过向 Redis 发送下面的命令,实现原子性的加锁操作:


SET key random_value NX PX 30000


关键点二:设置值的时候,放的是random_value。而不是你随便扔个“OK”进去。


先解释一下上面的命令中的几个参数的含义:


random_value:是由客户端生成的一个随机字符串,它要保证在足够长的一段时间内在所有客户端的所有获取锁的请求中都是唯一的。


NX:表示只有当要设置的 key 值不存在的时候才能 set 成功。这保证了只有第一个请求的客户端才能获得锁,而其它客户端在锁被释放之前都无法获得锁。


PX 30000:表示这个锁有一个 30 秒的自动过期时间。当然,这里 30 秒只是一个例子,客户端可以选择合适的过期时间。


再解释一下为什么 value 需要设置为一个随机字符串。这也是第三个关键点。


关键点三:value 的值设置为随机数主要是为了更安全的释放锁,释放锁的时候需要检查 key 是否存在,且 key 对应的值是否和我指定的值一样,是一样的才能释放锁。所以可以看到这里有获取、判断、删除三个操作,为了保障原子性,我们需要用 lua 脚本。


(基本上能答到这几个关键点,面试官也就会进入下一个问题了。常规热身送分题呀,朋友们,得记住了。)


集群模式


面试官就会接着问了:


经过刚刚的讨论,我们已经有较好的方法获取锁和释放锁。基于Redis单实例,假设这个单实例总是可用,这种方法已经足够安全。如果这个Redis节点挂掉了呢?


到这个问题其实可以直接聊到 Redlock 了。但是你别慌啊,为了展示你丰富的知识储备(疯狂的刷题准备),你得先自己聊一聊 Redis 的集群,你可以这样去说:


为了避免节点挂掉导致的问题,我们可以采用Redis集群的方法来实现Redis的高可用。

Redis集群方式共有三种:主从模式,哨兵模式,cluster(集群)模式


其中主从模式会保证数据在从节点还有一份,但是主节点挂了之后,需要手动把从节点切换为主节点。它非常简单,但是在实际的生产环境中是很少使用的。


哨兵模式就是主从模式的升级版,该模式下会对响应异常的主节点进行主观下线或者客观下线的操作,并进行主从切换。它可以保证高可用。


cluster (集群)模式保证的是高并发,整个集群分担所有数据,不同的 key 会放到不同的 Redis 中。每个 Redis 对应一部分的槽。


(上面三种模式也是面试重点,可以说很多道道出来,由于不是本文重点就不详细描述了。主要表达的意思是你得在面试的时候遇到相关问题,需要展示自己是知道这些东西的,都是面试的套路。)


在上面描述的集群模式下还是会出现一个问题,由于节点之间是采用异步通信的方式。如果刚刚在 Master 节点上加了锁,但是数据还没被同步到 Salve。这时 Master 节点挂了,它上面的锁就没了,等新的 Master 出来后(主从模式的手动切换或者哨兵模式的一次 failover 的过程),就可以再次获取同样的锁,出现一把锁被拿到了两次的场景。


锁都被拿了两次了,也就不满足安全性了。一个安全的锁,不管是不是分布式的,在任意一个时刻,都只有一个客户端持有。

目录
相关文章
|
11月前
|
存储 缓存 NoSQL
Redis常见面试题全解析
Redis面试高频考点全解析:从过期删除、内存淘汰策略,到缓存雪崩、击穿、穿透及BigKey问题,深入原理与实战解决方案,助你轻松应对技术挑战,提升系统性能与稳定性。(238字)
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
966 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
存储 NoSQL 定位技术
Redis数据类型面试给分情况
Redis常见数据类型包括:string、hash、list、set、zset(有序集合)。此外还包含高级结构如bitmap、hyperloglog、geo。不同场景可选用合适类型,如库存用string,对象存hash,列表用list,去重场景用set,排行用zset,签到用bitmap,统计访问量用hyperloglog,地理位置用geo。
711 5
|
缓存 NoSQL Java
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
890 6
|
存储 NoSQL Redis
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 +  无锁架构 +  EDA架构  + 异步日志 + 集群架构
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
502 4