看完这些Redis八股文,面试官直呼内行

988 阅读26分钟

1.redis 是什么?

redis 是 nosql(也是个巨大的 map) 单线程,但是可处理 1 秒 10w 的并发(数 据都在内存中) 使用 java 对 redis 进行操作类似 jdbc 接口标准对 mysql,有各类实现他的实现 类,我们常用的是 druid 其中对 redis,我们通常用 Jedis(也为我们提供了连接池 JedisPool) 在 redis 中,key 就是 byte redis 的数据结构(value): String,list,set,orderset,hash 每种数据结构对应不同的命令语句

2.redis 怎么使用?

先安装好 redis,然后运行,在 pom 文件中引入依赖,在要使用 redis 缓存的类 的 mapper.xml 文件配置 redis 的全限定名。引入 redis 的 redis.properties 文 件(如果要更改配置就可以使用)

3.应用场景

list(双向链表)

1 可以使用 redis 的 list 模拟队列,堆,栈

2 朋友圈点赞(一条朋友圈内容语句,若干点赞语句) 规定:朋友圈内容的格式:

1,内容: user:x:post:x content 来存储;点赞: post:x:good list 来存储;(把相应头像取出来显示)

4.为什么 redis 是单线程的都那么快

  • 1.数据存于内存
  • 2.用了多路复用 I/O
  • 3.单线程

5.redis 也可以进行发布订阅消息吗?

可以,(然后可以引出哨兵模式(后面会讲)怎么互相监督的,就是因为每隔 2 秒哨兵节点会发布对某节点的判断和自身的信息到某频道,每个哨兵订阅该频道 获取其他哨兵节点和主从节点的信息,以达到哨兵间互相监控和对主从节点的监 控)和很多专业的消息队列系统(例如 Kafka、RocketMQ)相比,Redis 的发 布订阅略显粗糙,例如无法实现消息堆积和回溯。但胜在足够简单

6.redis 能否将数据持久化,如何实现

能,将内存中的数据异步写入硬盘中,两种方式:RDB(默认)和 AOF

RDB 持久化原理:通过 bgsave 命令触发,然后父进程执行 fork 操作创建 子进程,子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对 原有文件进行原子替换(定时一次性将所有数据进行快照生成一份副本存储在硬 盘中)

优点:是一个紧凑压缩的二进制文件,Redis 加载 RDB 恢复数据远远快于 AOF 的方式。

缺点:由于每次生成 RDB 开销较大,非实时持久化,

AOF 持久化原理:开启后,Redis 每执行一个修改数据的命令,都会把这 个命令添加到 AOF 文件中。

优点:实时持久化。

缺点:所以 AOF 文件体积逐渐变大,需要定期执行重写操作来降低文件体积, 加载慢

7.主从复制模式下,主挂了怎么办?

redis 提供了 哨兵模式(高可用) 何谓哨兵模式?就是通过哨兵节点进行自主监控主从节点以及其他哨兵节点,发 现主节点故障时自主进行故障转移

8.哨兵模式实现原理?(2.8 版本或更高才有)

1.三个定时监控任务:

  • 1.1 每隔 10s,每个 S 节点(哨兵节点)会向主节点和从节点发送 info 命令获 取最新的拓扑结构
  • 1.2 每隔 2s,每个 S 节点会向某频道上发送该 S 节点对于主节点的判断以及当 前 Sl 节点的信息, 同时每个 Sentinel 节点也会订阅该频道,来了解其他 S 节点以及它们对主节点 的判断(做客观下线依据)
  • 1.3 每隔 1s,每个 S 节点会向主节点、从节点、其余 S 节点发送一条 ping 命令 做一次心跳检测(心跳检测机制),来确认这些节点当前是否可达

2.主客观下线

  • 2.1 主观下线:根据第三个定时任务对没有有效回复的节点做主观下线处理
  • 2.2 客观下线:若主观下线的是主节点,会咨询其他 S 节点对该主节点的判断, 超过半数,对该主节点做客观下线

3.选举出某一哨兵节点作为领导者

  • 来进行故障转移。选举方式:raft 算法。每个 S 节点有一票同意权,哪个 S 节点做出主观下线的时候,就会询问其 他 S 节点是否同意其为领导者。获得半数选票的则成为领导者。基本谁先做出客 观下线,谁成为领导者

9.redis 集群(采用虚拟槽方式,高可用)原理(和哨兵模式原理类似,3.0 版本或以上才有)

1.Redis 集群内节点通过 ping/pong 消息实现节点通信,消息不但可以传播节 点槽信息,还可以传播其他状态如:主从状态、节点故障等。因此故障发现也是 通过消息传播机制实现的,主要环节包括:主观下线(pfail)和客观下线(fail)

2.主客观下线:

  • 2.1 主观下线:集群中每个节点都会定期向其他节点发送 ping 消息,接收节点 回复 pong 消息作为响应。如果通信一直失败,则发送节点会把接收节点标记为 主观下线(pfail)状态。
  • 2.2 客观下线:超过半数,对该主节点做客观下线
  • 3.主节点选举出某一主节点作为领导者,来进行故障转移。
  • 4.故障转移(选举从节点作为新主节点)

10.缓存更新策略(即如何让缓存和 mysql 保持一致性)?

10.1 key 过期清除(超时剔除)策略

惰性过期(类比懒加载,这是懒过期):只有当访问一个 key 时,才会判断该 key 是否已过期,过期则清除。该策略可以最大化地节省 CPU 资源,却对内存非常 不友好。极端情况可能出现大量的过期 key 没有再次被访问,从而不会被清除, 占用大量内存。 定期过期:每隔一定的时间,会扫描一定数量的数据库的 expires 字典中一定数 量的 key,并清除其中已过期的 key。该策略是前两者的一个折中方案。通过调 整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得 CPU 和 内存资源达到最优的平衡效果。 (expires 字典会保存所有设置了过期时间的 key 的过期时间数据,其中,key 是 指向键空间中的某个键的指针,value 是该键的毫秒精度的 UNIX 时间戳表示的 过期时间。键空间是指该 Redis 集群中保存的所有键。) 问:比如这么个场景,我设计了很多 key,过期时间是 5 分钟,当前内存占用率 是 50%。但是 5 分钟到了,内存占用率还是很高,请问为什么? Redis 中同时使用了惰性过期和定期过期两种过期策略,即使过期时间到了,但 是有部分并没有真正删除,等待惰性删除。 为什么有定期还要有惰性呢?其实很简单,比如 10 万个 key 就要过期了,Redis 默认是 100ms 检查一波。如果他检查出 10 万个即将要清除,那他接下来的时 间基本都是在干这些清空内存的事了,那肯定影响性能,所以他只会部分删除, 剩下的等惰性

10.2 Redis 的内存淘汰策略

Redis 的内存淘汰策略是指在 Redis 的用于缓存的内存不足时,怎么处理需要新 写入且需要申请额外空间的数据。

  • noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用 的 key。
  • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key。
  • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中, 移除最近最少使用的 key。
  • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空 间中,随机移除某个 key。
  • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中, 有更早过期时间的 key 优先移除

11.如何防止缓存穿透?

(缓存穿透指的是查询一个根本不存在的数据,缓存层不命中,又去查存储层, 又不命中。但如果有大量这种查询不存在的数据的请求过来,会对存储层有较大 压力,若是恶意攻击,后果就)

  • 采用布隆过滤器,将所有可能存在的数据存到一个bitMap中,不存在的数据就会进行拦截。
  • 对查询结果为空的情况也进行缓存,缓存时间设置短一点,不超过5分钟。

12.无底洞优化?

造成原因:redis 分布式越来越多,导致性能反而下降,因为键值分布到更多的 节点上,所以无论是 Memcache 还是 Redis 的分布式,批量操作通常需要从不 同节点上获取,相比于单机批量操作只涉及一次网络操作,分布式批量操作 会 涉及多次网络时间。 即分布式过犹不及。

用一句通俗的话总结就是,更多的节点不代表更高的性能,所谓“无底 洞”就是说投入越多不一定产出越多。但是分布式又是不可以避免的,因为 访问量和数据量越来越大,一个节点根本抗不住,所以如何高效地在分布式缓存中批量操作是一个难点 优化思路

命令本身的优化,例如优化SQL语句等

  • 减少网络通信次数
  • 降低接入成本,例如客户端使用长连/连接池、NIO等

这里我们假设命令、客户端连接已经为最优,重点讨论减少网络操作次数 以Redis批量获取n个字符串为例,有三种实现方法,如下图所示:

  • 客户端n次get:n次网络+n次get命令本身
  • 客户端1次pipeline get:1次网络+n次get命令本身
  • 客户端1次mget:1次网络+1次mget命令本身

13.雪崩优化

如果缓存层由于某些原因不能提供服务,于是所有的请求都会达到存储层,存储 层的调用量会暴增,造成存储层也会级联宕机的情况

  • 1、保持缓存层服务器的高可用。 –监控、集群、哨兵。当一个集群里面有一台服务器有问题,让哨兵踢出去。
  • 2、依赖隔离组件为后端限流并降级。 比如推荐服务中,如果个性化推荐服务不可用,可以降级为热点数据。
  • 3、提前演练。 演练 缓存层crash后,应用以及后端的负载情况以及可能出现的问题。 对此做一些预案设定。

14.热点 key 优化

当前 key 是一个热点 key(例如一个热门的娱乐新闻),并发量非常大

  • 1、互斥锁: 只允许一个请求重建缓存。 其他请求等待缓存重建执行完,重新从缓存获取数据即可。

  • 2、用户过期 “物理”不过期, 逻辑设置过期时间(根据上一次更新时间,构建一个队列,主动去更新)

15.Redis 持久化机制

Redis 是一个支持持久化的内存数据库,通过持久化机制把内存中的数据同步到 硬盘文件来保证数据持久化。当 Redis 重启后通过把硬盘文件重新加载到内存, 就能达到恢复数据的目的。 实现:单独创建 fork()一个子进程,将当前父进程的数据库数据复制到子进程的 内存中,然后由子进程写入到临时文件中,持久化的过程结束了,再用这个临时 文件替换上次的快照文件,然后子进程退出,内存释放。

RDB 是 Redis 默认的持久化方式。按照一定的时间周期策略把内存的数据以快 照的形式保存到硬盘的二进制文件。即 Snapshot 快照存储,对应产生的数据文 件为 dump.rdb,通过配置文件中的 save 参数来定义快照的周期。( 快照可以 是其所表示的数据的一个副本,也可以是数据的一个复制品。 )

AOF:Redis 会将每一个收到的写命令都通过 Write 函数追加到文件最后,类似 于 MySQL 的 binlog。当 Redis 重启是会通过重新执行文件中保存的写命令来 在内存中重建整个数据库的内容。 当两种方式同时开启时,数据恢复 Redis 会优先选择 AOF 恢复

16 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题

一、缓存雪崩

我们可以简单的理解为:由于原有缓存失效,新缓存未到期间 (例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存 过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库 CPU 和内 存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整 个系统崩溃。

解决办法: 大多数系统设计者考虑用加锁( 最多的解决方案)或者队列的方式保证来保证 不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落 到底层存储系统上。还有一个简单方案就时讲缓存失效时间分散开。

二、缓存穿透

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导 致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回 空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库,这也 是经常提的缓存命中率问题。 解决办法;

  • 最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底 层存储系统的查询压力。

  • 另外也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数据 不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会 很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次 到缓冲中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。 5TB 的硬盘上放满了数据,请写一个算法将这些数据进行排重。如果这些数据是 一些 32bit 大小的数据该如何解决?如果是 64bit 的呢? 对于空间的利用到达了一种极致,那就是 Bitmap 和布隆过滤器(Bloom Filter)。

Bitmap: 典型的就是哈希表

缺点是,Bitmap 对于每个元素只能记录 1bit 信息,如果还想完成额外的功能, 恐怕只能靠牺牲更多的空间、时间来完成了。

布隆过滤器(推荐)

就是引入了 k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率 下,完成元素判重的过程。

它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别 率和删除困难。

Bloom-Filter 算法的核心思想就是利用多个不同的 Hash 函数来解决“冲突”。 Hash 存在一个冲突(碰撞)的问题,用同一个 Hash 得到的两个 URL 的值有可 能相同。为了减少冲突,我们可以多引入几个 Hash,如果通过其中的一个 Hash 值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的 Hash 函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这便是 Bloom-Filter 的基本思想。 Bloom-Filter 一般用于在大数据量的集合中判定某元素是否存在。

三、缓存预热

缓存预热这个应该是一个比较常见的概念,相信很多小伙伴都应该可以很容易的 理解,缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样 就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户 直接查询事先被预热的缓存数据!

解决思路:

  • 1、直接写个缓存刷新页面,上线时手工操作下;
  • 2、数据量不大,可以在项目启动的时候自动进行加载;
  • 3、定时刷新缓存;

四、缓存更新

除了缓存服务器自带的缓存失效策略之外(Redis默认的有6中策略可供选择), 我们还可以根据具体的业务需求进行自定义的缓存淘汰,常见的策略有两种:

  • (1)定时去清理过期的缓存;
  • (2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话 就去底层系统得到新数据并更新缓存。

两者各有优劣,第一种的缺点是维护大量缓存的 key 是比较麻烦的,第二种的缺 点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方 案,大家可以根据自己的应用场景来权衡。

五、缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核 心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根 据一些关键数据进行自动降级,也可以配置开关实现人工降级。 降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级 的(如加入购物车、结算)。 以参考日志级别设置预案:

  • (1)一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自 动降级;
  • (2)警告:有些服务在一段时间内成功率有波动(如在 95~100%之间),可以 自动降级或人工降级,并发送告警;
  • (3)错误:比如可用率低于 90%,或者数据库连接池被打爆了,或者访问量突 然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
  • (4)严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。 服务降级的目的,是为了防止 Redis 服务故障,导致数据库跟着一起发生雪崩问 题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见 的做法就是,Redis 出现问题,不去数据库查询,而是直接返回默认值给用户

17.热点数据和冷数据是什么

热点数据,缓存才有价值 对于冷数据而言,大部分数据可能还没有再次访问到就已经被挤出内存,不仅占 用内存,而且价值不大。频繁修改的数据,看情况考虑使用缓存

对于上面两个例子,寿星列表、导航信息都存在一个特点,就是信息修改频率不 高,读取通常非常高的场景。 对于热点数据,比如我们的某 IM 产品,生日祝福模块,当天的寿星列表,缓存 以后可能读取数十万次。再举个例子,某导航产品,我们将导航信息,缓存以后 可能读取数百万次。

数据更新前至少读取两次缓存才有意义。这个是最基本的策略,如果缓存 还没有起作用就失效了,那就没有太大价值了。 那存不存在,修改频率很高,但是又不得不考虑缓存的场景呢?有!比如,这个 读取接口对数据库的压力很大,但是又是热点数据,这个时候就需要考虑通过缓 存手段,减少数据库的压力,

比如我们的某助手产品的,点赞数,收藏数,分享 数等是非常典型的热点数据,但是又不断变化,此时就需要将数据同步保存到 Redis 缓存,减少数据库压力。

18.Memcache 与 Redis 的区别都有哪些

  • 存储方式 Memecache 把数据全部存在内存之中,断电后会挂掉,数据不 能超过内存大小。 Redis 有部份存在硬盘上,redis 可以持久化其数据
  • 数据支持类型 memcached 所有的值均是简单的字符串,redis 作为其替代 者,支持更为丰富的数据类型 ,提供 list,set,zset,hash 等数据结构的存储
  • 使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协 议不一样。 Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数 的话,会浪费一定的时间去移动和请求。
  • value 值大小不同:Redis 最大可以达到 1gb;memcache 只有 1mb。 5)redis 的速度比 memcached 快很多
  • Redis 支持数据的备份,即 master-slave 模式的数据备份

19.单线程的 redis 为什么这么快

  • 纯内存操作
  • 单线程操作,避免了频繁的上下文切换
  • 采用了非阻塞 I/O 多路复用机制

20.Redis 为什么是单线程的

官方 FAQ 表示,因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会 有很多麻烦!)Redis 利用队列技术将并发访问变为串行访问

  • 绝大部分请求是纯粹的内存操作(非常快速)
  • 采用单线程,避免了不必要 的上下文切换和竞争条件

非阻塞 IO 优点:

  • 速度快,因为数据存在内存中,类似于 HashMap,HashMap 的优势就是查 找和操作的时间复杂度都是 O(1)
  • 支持丰富数据类型,支持 string,list,set,sorted set,hash
  • 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行, 要么全部不执行
  • 丰富的特性:可用于缓存,消息,按 key 设置过期时间,过期后将会自动删 除如何解决 redis 的并发竞争 key 问题 同时有多个子系统去 set 一个 key。这个时候要注意什么呢? 不推荐使用 redis 的事务机制。因为我们的生产环境,基本都是 redis 集群环境,做了数据分片操 作。你一个事务中有涉及到多个 key 操作的时候,这多个 key 不一定都存储在 同一个 redis-server 上。因此,redis 的事务机制,十分鸡肋。(1)如果对这个 key 操作,不要求顺序: 准备一个分布式锁,大家去抢锁,抢到 锁就做 set 操作即可 ;(2) 如果对这个 key 操作,要求顺序: 分布式锁+时间戳。 假设这会系统 B 先 抢到锁,将 key1 设置为{valueB 3:05}。接下来系统 A 抢到锁,发现自己的 valueA 的时间戳早于缓存中的时间戳,那就不做 set 操作了。以此类推。(3) 利用队列,将 set 方法变成串行访问也可以 redis 遇到高并发,如果保证读 写 key 的一致性 对redis的操作都是具有原子性的,是线程安全的操作,你不用考虑并发问题,redis 内部已经帮你处理好并发的问题了。

21.Redis 集群方案应该怎么做?都有哪些方案?

1.twemproxy,大概概念是,它类似于一个代理方式, 使用时在本需要连接 redis 的地方改为连接 twemproxy, 它会以一个代理的身份接收请求并使用 一致性 hash 算法,将请求转接到具体 redis,将结果再返回 twemproxy。 缺点: twemproxy 自身单端口实例的压力,使用一致性 hash 后,对 redis 节点数量改变时候的计算值的改变,数据无法自动移动到新的节点。

2.codis,目前用的最多的集群方案,基本和 twemproxy 一致的效果,但它支 持在 节点数量改变情况下,旧节点数据可恢复到新 hash 节点

3.redis cluster3.0 自带的集群,特点在于他的分布式算法不是一致性 hash,而 是 hash 槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。

22.有没有尝试进行多机 redis 的部署?如何保证数据一致的?

主从复制,读写分离 一类是主数据库(master)一类是从数据库(slave),主数据库可以进行读写操 作,当发生写操作的时候自动将数据同步到从数据库,而从数据库一般是只读的, 并接收主数据库同步过来的数据,一个主数据库可以有多个从数据库,而一个从 数据库只能有一个主数据库。

33.对于大量的请求怎么样处理

redis 是一个单线程程序,也就说同一时刻它只能处理一个客户端请求; redis 是通过 IO 多路复用(select,epoll, kqueue,依据不同的平台,采取不 同的实现)来处理多个客户端请求的

34.Redis 常见性能问题和解决方案?

(1) Master 最好不要做任何持久化工作,如 RDB 内存快照和 AOF 日志文件

(2) 如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步 一次

(3) 为了主从复制的速度和连接的稳定性, Master 和 Slave 最好在同一个局 域网内

(4) 尽量避免在压力很大的主库上增加从库

(5) 主从复制不要用图状结构,用单向链表结构更为稳定,即: Master <- Slave1 <- Slave2 <- Slave3

35.为什么 Redis 的操作是原子性的,怎么保证原子性的?

对于 Redis 而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行, 要么不执行。 Redis 的操作之所以是原子性的,是因为 Redis 是单线程的。 Redis 本身提供的所有 API 都是原子操作,Redis 中的事务其实是要保证批量操 作的原子性。 多个命令在并发中也是原子性的吗? 不一定, 将 get 和 set 改成单命令操作,incr 。使用 Redis 的事务,或者使用 Redis+Lua==的方式实现

36.Redis 事务

Redis 事务功能是通过 MULTI、EXEC、DISCARD 和 WATCH 四个原语实现的 Redis 会将一个事务中的所有命令序列化,然后按顺序执行。

1.redis 不支持回滚“Redis 在事务失败时不进行回滚,而是继续执行余下的命 令”, 所以 Redis 的内部可以保持简单且快速。

2.如果在一个事务中的命令出现错误,那么所有的命令都不会执行;

3.如果在一个事务中出现运行错误,那么正确的命令会被执行。

  • MULTI 命令用于开启一个事务,它总是返回 OK。 MULTI 执行之后,客户 端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到 一个队列中,当 EXEC 命令被调用时,所有队列中的命令才会被执行。
  • EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令 执行的先后顺序排列。 当操作被打断时,返回空值 nil。
  • 通过调用 DISCARD,客户端可以清空事务队列,并放弃执行事务, 并且客 户端会从事务状态中退出。
  • WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。 可以 监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执 行,监控一直持续到 EXEC 命令。

37.Redis 实现分布式锁

Redis 为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户 端对 Redis 的连接并不存在竞争关系 Redis 中可以使用 SETNX 命令实现分布式 锁。 将 key 的值设为 value ,当且仅当 key 不存在。 若给定的 key 已经存在, 则 SETNX 不做任何动作

解锁:使用 del key 命令就能释放锁

解决死锁:

  • 通过 Redis 中 expire()给锁设定最大持有时间,如果超过,则 Redis 来帮我 们释放锁。
  • 使用 setnx key “当前系统时间+锁持有的时间”和 getset key “当前系 统时间+锁持有的时间”组合的命令就可以实现。

福利

关注微信公众号:程序员小R,回复"666",获取超过2G的面试题集合

本文使用 mdnice 排版