Redis面试题

Redis的key和value可以存储的最大值分别是多少

虽然Key的大小上限为512M,但是一般建议key的大小不要超过1KB,这样既可以节约存储空间,又有利于Redis进行检索,value的最大值也是512M,对于String类型的value值上限为512M,而集合、链表、哈希等key类型
单个元素的value上限也为512M。

Redis的主从模式,一主两从有几种方式,有什么优缺点

  1. 一个master下挂两个slave,优点是slave同步速度快,缺点是master压力大
  2. 一个master下挂一个slave,这个slave下再挂一个slave,优点是master压力小,缺点是后者slave同步速度慢

Redis的哨兵模式,当master挂了之后,是怎么从剩余的slave中选择新的master的

  1. 先比较优先级,默认为100,数字越小优先级越高,越容易成为master
  2. 再比较数据的新旧程度
  3. 比较id

Redis的集群模式的优缺点

  1. 方便扩容和缩容
  2. 方便快速定位,插入时是哪个槽,查询时就是哪个槽
  3. 有可能丢数据,某个master节点没来得及同步数据给slave时,master节点挂掉了

如何用Redis来实现一个抽奖程序,你会怎么实现?

  1. 利用set
  2. sadd添加uid进set
  3. smembers查看所有uid,
  4. randmember从set随机选一个uid(可以指定选1个,还是选3个),不会删除uid
  5. spop也有随机的效果,但是会删除uid

Redis有哪些数据结构?分别有哪些典型的应用场景?

Redis的数据结构有:

  1. 字符串:可以用来做最简单的数据,可以缓存某个简单的字符串,也可以缓存某个json格式的字符串,Redis分布式锁的实现就利用了这种数据结构,还包括可以实现计数器、分布式ID
  2. 哈希表:可以用来存储一些key-value对,更适合用来存储对象
  3. 列表:Redis的列表通过命令的组合,既可以当做栈,也可以当做队列来使用,可以用来缓存类似微信公众号、微博等消息流数据
  4. 集合:和列表类似,也可以存储多个元素,但是不能重复,集合可以进行交集、并集、差集操作,从而可以实现类似,我和某人共同关注的人、朋友圈点赞等功能
  5. 有序集合:集合是无序的,有序集合可以设置顺序,可以用来实现排行榜功能

Redis分布式锁底层是如何实现的?

  1. 首先利用setnx来保证:如果key不存在才能获取到锁,如果key存在,则获取不到锁
  2. 然后还要利用lua脚本来保证多个redis操作的原子性
  3. 同时还要考虑到锁过期,所以需要额外的一个看门狗定时任务来监听锁是否需要续约
  4. 同时还要考虑到redis节点挂掉后的情况,所以需要采用红锁的方式来同时向N/2+1个节点申请锁,都申请到了才证明获取锁成功,这样就算其中某个redis节点挂掉了,锁也不能被其他客户端获取到

Redis主从复制的核心原理

全量同步:

  1. 一般发生在从节点初始化的时候
  2. 从节点发送SYNC命令连接主节点
  3. 主节点接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件,并使用缓冲区replication buffer记录在这个过程中接收到的写命令
  4. 主节点BGSAVE命令执行完后,向所有从节点发送RDB文件,并在发送缓冲区replication buffer记录的写命令
  5. 从节点收到RDB文件后丢弃所有旧数据,载入收到的RDB文件中的数据
  6. 主节点RDB文件发送完毕后,开始向从节点发送缓冲区replication buffer中的写命令
  7. 从节点完成RDB的载入后,开始接收客户端命令,并执行来自主节点缓冲区replication buffer的写命令

增量同步
Redis主节点每执行一个写命令就会向从节点异步发送相同的写命令,从节点接收并执行收到的写命令

缓存穿透、缓存击穿、缓存雪崩分别是什么

缓存中存放的大多都是热点数据,目的就是防止请求可以直接从缓存中获取到数据,而不用访问Mysql。

  1. 缓存雪崩:如果缓存中某一时刻大批热点数据同时过期,那么就可能导致大量请求直接访问Mysql了,解决办法就是在过期时间上增加一点随机值,另外如果搭建一个高可用的Redis集群也是防止缓存雪崩的有效手段
  2. 缓存击穿:和缓存雪崩类似,缓存雪崩是大批热点数据失效,而缓存击穿是指某一个热点key突然失效,也导致了大量请求直接访问Mysql数据库,这就是缓存击穿,解决方案就是考虑这个热点key不设过期时间
  3. 缓存穿透:假如某一时刻访问redis的大量key都在redis中不存在(比如黑客故意伪造一些乱七八糟的key),那么也会给数据造成压力,这就是缓存穿透,解决方案是使用布隆过滤器,它的作用就是如果它认为一个key不存在,那么这个key就肯定不存在,所以可以在缓存之前加一层布隆过滤器来拦截不存在的key

Redis和Mysql如何保证数据一致

  1. 先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不一致
  2. 先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中,这种方案能解决1方案的问题,但是在高并发下性能较低,而且仍然会出现数据不一致的问题,比如线程1删除了Redis缓存数据,正在更新Mysql,此时另外一个查询再查询,那么就会把Mysql中老数据又查到Redis中
  3. 延时双删,步骤是:先删除Redis缓存数据,再更新Mysql,延迟几百毫秒再删除Redis缓存数据,这样就算在更新Mysql时,有其他线程读了Mysql,把老数据读到了Redis中,那么也会被删除掉,从而把数据保持一致

1、什么是redis?

redis是一个内存数据库,数据的读写操作都在内存中进行,因此速度非常快,常用于缓存,消息队列,分布式锁等场景。

2、Redis 和 Memcached 有什么区别?

首先两者都是内存数据库,性能非常高,但是redis 有更丰富的数据结构,数据可以持久化,支持集群,还有发布订阅、lua脚本、事务等功能,因此使用redis更多一点。

3、为什么用 Redis 作为 MySQL 的缓存?

redis兼具高性能、高并发两大特性,高性能是因为redis对于数据的读写操作都是在内存中进行的,因此性能非常高,高并发是指redis的单机吞吐率是10w,大约是mysql的10倍左右。

4、Redis 数据类型以及使用场景分别是什么?

String,主要用于缓存对象等;

list,主要用于消息队列,但是存在着生产者无法自动生成全局唯一ID,无法以消费组形式消费等问题;

hash,主要用于缓存对象等;

set,主要用于聚合计算,例如点赞,共同关注等;

zset,主要用于排行榜,电话,姓名排序等;

bitmap,主要用于记录签到情况,判断登录状态等;

hyperloglog,主要用于百万的数据统计等;

geo,主要用于存储位置;

stream,主要用于消息队列,相对于list,能解决list存在的问题。

5、五种常见的 Redis 数据类型是怎么实现?

String:sds

list:quicklist

hash:listpack 和 哈希表

set:哈希表和整数集合

zset:listpack 和 跳表

6、listpack是什么?

listpack也叫紧凑列表,是用一块连续的内存空间来保存数据,为了节省内存空间,还使用多种编码方式来表示不同长度的数据。

7、Redis 是单线程吗?

不是单线程,redis的单线程是指接收请求,解析请求,处理请求内容,返回结果这个过程是单线程的,但是redis还会在后台创建关闭文件,aof刷盘,释放内存的线程,主要也是因为这些操作比较费时。

8、Redis 单线程模式是怎样的?

当有多个客户端链接时,会采用IO多路复用,epoll wait会发现事件然后分发给事件处理器,然后通过连接事件处理函数、读事件处理函数、写事件处理函数分别进行处理,连接事件处理函数会调用accept接收连接,然后将已连接的socket添加到epoll中,并注册读事件处理函数或写事件处理函数,读事件处理函数会调用read接收数据,写事件处理函数会调用write发送数据。写事件处理函数会将准备好的的数据发送到队列中,读事件处理函数,也会在数据准备完成后添加到发送队列,然后同时将执行结果加入到缓存中。

9、Redis 采用单线程为什么还这么快?

redis 的大部分操作都在内存中完成,并采用了高效的数据结构;redis是单线程的,避免线程之间的竞争;redis采用了IO多路复用机制处理大量的客户端socket请求,因此速度比较快。

10、Redis 6.0 之前为什么使用单线程?Redis 6.0 之后为什么引入了多线程?

因为制约redis性能的一直不是cpu,因此单线程就足够,6.0之后考虑到redis的性能瓶颈受限于网络IO,因此引入多个IO线程处理网络请求,但对任务的处理过程仍然是单线程。

11、Redis 如何实现数据不丢失?

一共有三种方式, 第一种是RDB,其是将写命令以追加写的方式写入到文件中,第二种是RDB,它是将某一个时刻的数据以二进制的形式写入到磁盘,第三种是混合存储模式,集成了RDB和AOF的优点,是4.0新增的方式。

12、AOF 日志过大,会触发什么机制?

当写操作命令越来越多时,会导致AOF日志过大,此时会触发重写机制,缩小AOF日志的大小,举个例子:对同一个key值的两次value更新,只会保存最后一个。

13、重写 AOF 日志的过程是怎样的?

为了减少对于主线程的阻塞,这个过程通常是由子线程来完成的,为了保证主线程和子线程的内存数据的一致性,在子线程重写的过程时,会同时将数据发送到AOF缓冲区和AOF重写缓冲区,然后当子线程重写完成后,会给主线程发送指令,此时主线程会有两个操作,第一个操作是读取重写缓冲区的内容,将其加入到AOF文件中,第二个操作是将新的AOF文件覆盖原来的AOF文件,从而实现主线程和子线程的数据一致。

14、RDB 快照是如何实现的呢?

AOF日志是记录操作指令,因此当redis故障恢复时,一旦AOF文件过大,就会导致恢复缓慢,那么RDB就登场了,RDB是存储某一时刻的数据的二进制文件,这也当恢复时,采用RDB的效率会更高一点,直接将RDB文件读入内存即可。

15、RDB 在执行快照的时候,数据能修改吗?

可以的,关键在于写时复制技术,但此时RDB出来的数据就不是最新的数据了,只能当下一次快照时,才能读取到最新的数据。

16、为什么会有混合持久化?

RDB的优点在于恢复数据很快,但缺点在于快照的间隔很难保证,太快会导致对性能的负荷较大,太慢又会导致数据的缺失较多。

AOF的优点在于数据的缺失较少,但恢复数据的过程较慢。

因此为了结合二者的优点,在进行AOF日志重写的过程时,前半段会通过RDB的方式,后半段追加写入的内容采用AOF的方式,因此新的AOF日志前半段是RDB的格式,后半段是AOF的格式,优点就是让redis能更快的启动,但是缺点是让AOF的文件可读性变得较差。

17、Redis 如何实现服务高可用?

①主从复制,同时主节点进行写操作或读操作,从节点只进行读操作,读写分离。

②哨兵模式,为了避免主从复制出现问题手动恢复的情况出现,通过哨兵模式监控主从节点的工作情况,并进行故障转移。

③切片集群,当单机存储的缓存数据太大时,可以采用切片集群的方式将数据分散到多台机器上,从而避免对单机的负荷太大,提高读写性能。

18、集群脑裂导致数据丢失怎么办?

脑裂是指当主从断开后,由于只是网络问题,客户端认为当前主还未下线,故还在向主发送数据,但由于网络问题,这些数据都无法同步给从节点,这时哨兵发现主出问题,故将其中一个从升为新主,而主则降为从,此时进行全量同步时,就会导致旧主的缓冲区的数据全部丢失。

解决方法:通过设置参数,如延迟的时间和从连接的数目等,进而可以限制当主心跳监测不到时,禁止向原旧主发送数据,并且只将数据写到新主上。

19、Redis 使用的过期删除策略是什么?

惰性删除+定期删除策略。

惰性删除:不主动检测过期的key,只要当要使用时,发现其过期,旧删除该key

定时删除:按照一定的时间间隔删除过期key

定期删除:每隔一定时间,随机选取20个key检测是否过期,如果超过其1/4过期,则重新选择20个key进行检测,如果不超过1/4,则结束该过程

使用惰性删除+定期删除策略也是为了平衡cpu的使用以及对于内存的浪费。

20、Redis 内存满了,会发生什么?

当redis运行内存达到某一个阈值时,就会触发内存淘汰机制,一共有八种。

①不进行数据淘汰

②随机淘汰过期的键值

③优先淘汰更早过期的键值

④优先淘汰最久未被使用的设置了过期时间的键值

⑤优先淘汰最少使用的设置了过期时间的键值

⑥随机淘汰任意键值

⑦优先淘汰最久未被使用的键值

⑧优先淘汰最少使用的键值

21、LRU 算法和 LFU 算法有什么区别?

LRU是指淘汰最近最少使用的数据(时间)

LFU是指淘汰最近最少次数使用的数据(次数)

LRU是通过链表实现的,LFU是通过在结构体中增加数据的访问频次信息来实现的。

22、了解缓存雪崩、缓存击穿、缓存穿透吗?

缓存穿透是指该数据都不存在于数据库和缓存中,避免缓存穿透的方法主要有设置布隆过滤,或者缓存空对象来解决。

缓存击穿是指某热点数据过期,此时大量的请求打到数据库上,给数据库造成了巨大的压力,解决方法主要有互斥锁和逻辑过期,逻辑过期的一致性较差。

缓存雪崩主要是指大量的key同时失效造成的访问压力过大,解决方法主要有给不同的key随机设置过期时间,若是redis宕机引发的,可以设置集群或者增加多级缓存策略来解决。

23、如何保证数据库和缓存的数据一致性?

先更新数据库,再删除缓存。(也会出现数据不一致的情况,但由于更新缓存的速度远远快于写入数据库的速度,故出现的概率很低) 解决方案:可以通过加分布式锁或者加入较短的过期时间来保证

先删除缓存,再更新数据库。 会有极大可能发生数据不一致的情况,解决方案:延迟双删

24、redis的大key如何处理?

大key指的是key 所对应的value很大,它的危害主要有:会造成内存分布不均,会造成客户端超时阻塞,从客户端反应就是迟迟未能响应,可以通过scan命令或一些工具查找大key,解决方案可以通过分批次删除或异步删除来解决。

25、redis的管道有什么用?

可以解决多个命令执行时的网络等待

26、为什么redis不支持事务回滚?

设计理念主要是简单高效,支持事务回滚这种功能与设计理念相悖,其次发生错误主要是编程错误,主要是在开发阶段,生产环境中很少会出现,因此没必要设计这个功能。

27、如何使用redis实现分布式锁?

使用set nx ex 指令,优点在于性能高效,实现简单, 但是缺点在于超时时间不好设置,以及在集群模式下,很容易出现给主加锁,但是没同步到其他节点,就宕机了,仍然还能给新主加锁,就是所谓的分布式锁不可靠,因此在集群模式下,我们可以设置,当主节点和半数以上的从节点加锁成功才认为分布式锁加锁成功,否则就认为失败,回滚之前加锁成功的节点。

  • 22
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值