Redis面试题复习整理(一)缓存穿透、缓存击穿、缓存雪崩、内存淘汰策略、Redis持久化机制

1、Redis有哪些数据结构

基本的数据结构有:

  • String字符串
  • List列表
  • Hash哈希对象
  • Set集合
  • SortedSet有序集合,set基础上增加了分值。

高级数据结构有:

  • Hyper log log,不精确的去重计数功能,比较适合用来做大规模的去重统计,例如网站的UV,访问量。
  • Bitmap,位图,支持按bit为来存储信息,可以用来实现布隆过滤器。
  • Stream,主要用于消息队列,类似于Kafka,可以认为是pub/sub的改进版。提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并能记住每一个客户端的访问位置,并保证消息不丢失。
  • Geo ,Redis3.2新特性,可以将用户给定的地理位置信息存储起来,并做位置距离计算或者根据半径计算位置等。
  • Pipeline,可以批量执行一组指令,一次性返回全部结果,可以减少频繁的请求应答。

2、Redis是单线程还是多线程的?

Redis4之前是完全单线程的,在Redis4.0时引入了多线程,但是只是用来做后台处理,核心流程还是完全单线程的。(接受命令、解析命令、执行命令、返回结果等)。

Redis6.0 多线程用于网络IO阶段,在接接受命令和返回结果阶段,执行命令时还是单线程的。

因为Redis是基于内存的,不需要通过多线程来提高cpu的利用率,Redis的瓶颈最有可能是机器的内存大小或者网络带宽。使用多线程会造成额外的性能开销,而且还要解决多线程编程的共享资源的并发控制问题。

3、为什么Redis使用单线程 还是很快?

因为Redis是基于内存的,并且有高效的数据结构。

使用IO多路复用模型,开发了自己的网络事件处理器,使redis可以更高效的进行网络通信。

单线程操作避免了频繁的上下文切换,和多线程的竞争。

4、什么是缓存穿透,缓存击穿,缓存雪崩?

缓存穿透:查询不存在Redis中的key,就会是请求到达数据库查询,如果这时候有大量的请求查询不存在的key就会使数据库负载过大,就像把缓存穿透了直接打在了数据库上。

解决方案

  1. 缓存空对象:如果数据库查不到就把这个key保存在Redis中,再次访问数据库时,在缓存层直接返回空值。

  2. 使用布隆过滤器:将所有存在的key提前存入布隆过滤器中,在访问缓存之前,先通过布隆过滤器拦截,若请求的是不存在的key,则直接返回空值。

    如果布隆过滤器判断某个key不存在,那一定不存在,但是判断某个key存在时,这个key实际可能不存在,(有一定的误判率)。

另:布隆过滤器使用的是bitmap数据结构,后面会介绍布隆过滤器的原理。

缓存击穿:某一个热点的key失效了,这时大量的并发请求直接到达数据库。

解决方案

  1. 设置永不过期:对于一些热点数据可以设置为永不过期。
  2. 加互斥锁:对数据的访问加互斥锁,只有拿到锁的才可以访问数据库,其他线程只能等待。这个线程访问过后,缓存中的数据将被重建,然后其他线程就可以直接从缓存中取值了。

缓存雪崩:同一时间大规模的key失效,可能是Redis宕机,也可能是设置了相同的过期时间。

解决方案

  1. 避免同时过期:设置过期时间时,随机加一个随机值,避免大量key同时过期。
  2. 构建高可用的Redis缓存:搭建Redis集群,提高Redis的容灾性。
  3. 构建多级缓存:增加本地缓存,在存储层前多加一级屏障,降低到达数据库的几率。
  4. 使用熔断机制:对存储层增加限流措施,当请求超出限制时,对其提供降级措施,例如:当请求到达一定阈值,直接返回“系统繁忙“等提示,防止过多的请求到达数据库上,这样可以保证一部分用户还可以使用,其他用户多刷新几次也能得到结果。

5、Redis删除数据的策略有哪些?

  • 惰性删除:每次获取键时都检查键是否过期,如果过期就删除这个键,当时对内存不太友好。
  • 定时删除:用一个定时器来负责监视key,是否有过期的key,有就删除。
  • 定期删除+惰性删除:默认时间为100ms,程序就对数据进行一次检查,并不是没100ms就将所有key都检查一次,而是随机抽取进行检查,在配合上惰性删除,Redis的性能就得到的提升。

6、说一说Redis的内存淘汰策略

当Redis的内存空间已经用满时,Redis将根据配置的驱逐策略进行相应的淘汰,具体有以下几种:

  1. noeviction:默认策略,不淘汰任何key,直接返回错误。
  2. volatile-lru:在设置了过期时间的key中选择 最近最少使用的key进行淘汰。
  3. volatile-ttl:在设置了过期时间的key中选择 将要过期的key进行淘汰。
  4. volatile-random:在设置了过期时间的key中 随机选择key进行淘汰。
  5. allkeys-lru:在所有key中,选择最近最少使用的key进行淘汰。
  6. allkeys-random:在所有key中,随机选择key进行淘汰。
  7. 禁止淘汰数据。

对应的淘汰算法

  • FIFO:先进先出,新访问的数据插入到FIFO队列尾部,数据在FIFO队列中顺序移动,淘汰FIFO队列头部的数据。

  • LRU:最近最少使用,判断最近被使用的时间,目前最远的数据优先被淘汰。

    新数据插入到链表尾部,每当缓存数据被访问,则将数据移到链表头部,当链表满时,将链表尾部的数据丢弃。

  • LFU:最不经常使用,在一段时间内,数据被使用次数最少的优先被淘汰。

    把数据加入到链表中,按频次排序,一个数据被访问过,把它的频次+1,发生淘汰时,把频次低的淘汰掉。

7、Redis的持久化机制

Redis的持久化机制有:RDBAOF混合持久化(RDB+AOF)(Redis4.0引入)

  • RDB
    • 类似于快照,在指定的时间间隔内,将数据库的状态保存到一个RDB文件中,RDB持久化所生成的文件是一个压缩的二进制文件。
    • 有两个Redis命令可以用于生成一个RDB文件,一个是save,另一个是bgsave
      • save命令会直接阻塞服务器进程,而bgsave会生成一个子进程然后由子进程创建RDB文件,主进程仍然可以继续处理命令请求。
    • 用户可以通过设置save选项,让服务器每隔一段时间自动执行一个bgsave命令。
      • redis默认的设置为:
        1. save 900 1 # 900秒内有一个key修改,就执行保存命令
        2. save 300 10
        3. save 60 10000
      • 当任意一个保存条件被满足时就会自动执行bgsave命令。
    • RDB的优点:
      • RDB文件是经过压缩的二进制文件,占用空间小
      • 再恢复大数据集时的速度比AOF快
      • RDB可以最大化redis的性能
    • RDB缺点:
      • RDB在服务器出现故障时容易造成数据的丢失,用户可以通过自己配置来控制持久化的频率,如果太频繁就会影响redis的性能。通常设置5分钟,如果Redis出现宕机的情况,最多只会丢失5分钟的数据。
  • AOF
    • 以日志的形式记录服务器所处理的每一个写、删除操作,以文本的方式记录,并在服务器启动时,通过重新执行这些命令来还原数据集。
    • AOF默认是关闭的。
    • AOF优点
      • AOF重写可以产生一个新的AOF文件,这个新的文件比旧的AOF文件小,但保存的数据状态一样。
      • AOF支持秒级持久化,就算服务器故障,也只会丢失1秒钟的数据。
        • 为了提高文件的写入效率,现代操作系统中用户调用写入命令时,会先将数据写入到缓冲区中,然后系统提供了同步的函数,来将缓冲区的数据同步到文件中。
        • redis的同步选项有三个默认是如果距离上次同步aof文件的操作超过1秒钟,就再次对文件进行同步
    • 缺点
      • 相同的数据集,文件大小一般比RDB大。
      • 数据恢复比rdb慢。
  • 混合持久化
    • 混合持久化只发生于AOF重写的过程中,重写后的AOF文件前半段是RDB格式的海量数据,后半段是AOF格式的增量数据。
AOF重写功能的原理

首先从数据库中读取键当前时刻的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令。

原先往set中三次一共添加了三个值,重写时,先读取数据库中set的值,然后一次性往set中添加这三个值,这样就减少了数据冗余只需要一条命令就保存了数据库当前的状态。

为什么需要AOF重写文件

因为AOF是以日志的形式追加文件的,随着写入命令的不断增加,AOF文件中的内容会越来越多,文件的体积也会也来越大,所以需要AOF重写文件来避免对redis服务器造成影响。

AOF后台重写的原理,如何解决AOF后台重写后造成的数据不一致问题?

AOF重写会有大量的写入操作(因为Redis的命令需要在客户端上下文中执行,因此Redis在执行重写时会生成一个不带网络连接的伪客户端来执行Redis命令,为什么不带网络连接呢? 因为重写时根据原先的AOF文件进行的而不是网络连接),如果使用主线程来执行会被长时间阻塞而不能处理用户请求,所以Redis决定将重写操作放在一个子进程中执行。

这样做服务器的主进程仍然可以继续处理命令请求,但是在子进程重写的过程中主进程可能会处理新的写入命令,从而导致数据库状态和重写后的状态不一致的情况

为了解决这个问题,Redis服务器设置了一个AOF 重写缓冲区,这个重写缓冲区在服务器创建子进程之后开始使用。这个时候服务器在继续处理命令请求时会进行如下三个操作:

  1. 执行客户端发来的命令
  2. 将执行后的写命令追加到AOF缓冲区中
  3. 将执行后的写命令追加到AOF重写缓冲区中

子进程在后台重写的过程中,主进程执行的写入命令会追加到重写缓冲区中,在子进程执行完会后会给主进程发送一个信号,主进程收到这个信号后,执行一个信号处理函数(会对服务器进程造成阻塞),来将重写缓冲区中的数据追加到新的AOF文件中,这时新的AOF文件所保存的数据库状态将和服务器中数据库的状态保持一致。

8、说一说Redis的主从复制

一个服务器想要复制另一个服务器,那么这个主动复制的服务器为从服务器,被复制的服务器为主服务器

使用salveof命令

旧版的复制功能分为两步:同步命令传播两个操作。

同步是将从服务器的数据库状态更新至主服务器的数据库状态。

  • 首先从服务器执行同步操作,即向主服务器发送sync命令
  • 收到sync命令的主服务器执行bgsave命令,生成一个RDB文件,并用一个缓冲区记录从现在开始的所有写命令。
  • bgsave命令执行完毕后,将生成的RDB文件发送给从服务器,从服务器载入这个RDB文件,将数据库的状态更新为主服务器的数据库状态。
  • 之后主服务器在将记录在缓冲区中的所有写命令发送给从服务器,从服务器在执行这些命令,实现数据库的同步。

因为执行bgsave命令的过程中也就是生成RDB文件的过程中,是由子进程执行的,而主进程仍然可以继续执行写入命令,所以需要这个缓冲区来存储。

同步执行完之后就到了命令传播阶段,每当主服务器执行写入命令的时候,就会将该命令发送给从服务器,从服务器执行了相同的命令后,主从服务器数据库就又回到了相同的状态。

但是旧版复制功能有缺陷:

从服务器的复制有两种状态:

  1. 初次复制,从服务器以前没有复制过任何主服务器,或者当前复制的服务器和之前复制的主服务器不同。
  2. 断线后的重复制:在命令传播阶段从服务器断线,从服务器后通过重连重新连接到了主服务器,继续复制主服务器。

而缺陷就在于对于断线后的重复制,断线重连后的复制主服务器会把包含所有命令的RDB文件发送给从服务器,但实际上,从服务器的数据库状态与主服务器的数据库状态不同的只是断线后主服务器执行的命令,没有必要同步之前所有的命令

因此就有了新版的复制功能

为了解决部分重同步所出现的问题,Redis2.8之后出现了psync命令来替代sync命令

psync有两个模式:完整重同步部分重同步

  • 完整重同步用于处理初次复制的情况。
  • 部分重同步用于处理断线重连后的同步情况。断线重连后主服务器只向从服务器发送断线后执行的写命令。

部分重同步原理

部分重同步有三部分组成:主服务器的复制偏移量和从服务器的复制偏移量、主服务器的复制积压缓冲区、服务器的ID。

复制偏移量:

  • 主服务器和从服务器在执行复制的过程中都维护一个自己的复制偏移量,每次主服务器向从服务器发送n个字节的数据时,就将复制偏移量加n,从服务器收到后也将自己的复制偏移量加n。通过复制偏移量,就可以判断出主从服务器是否处于同步的状态。

复制积压缓冲区:

  • ​ 是由主服务器维护的一个固定长度的FIFO队列,默认大小为1MB。主服务器接收到写命令后不仅会将命令发送给从服务器,还会将命令放入到复制积压缓冲区中。所以该缓冲区中会保存了最近执行的写命令,并且在复制积压缓冲区中还对应存储着每个字节对应的复制偏移量。
  • 从服务器断线重连后,通过psync命令将自己的复制偏移量发送给主服务器。然后主服务器来判断执行那种同步操作。
    • 如果从服务器的复制偏移量offset+1的数据不在复制积压缓冲区中,那么就执行完整重同步
    • 如果offset+1的数据在缓冲区中,就执行部分重同步。

服务器id:

  • 如果从服务器重连后的和第一次复制时主服务器发送的服务器id不一致,那就说明断线前连接的的主服务器并不是现在连接的,因此要执行完整重同步。否则执行部分重同步。
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值