Redis高频面试题

redis单线程为什么那么快

  • 在内存中操作
  • 核心是基于非阻塞的I/O多路复用机制(主进程只会处理命令,不会进行磁盘IO操作)
  • 单线程反而避免了多线程频繁上下文切换带来的性能问题
    在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述

过期键的删除策略

惰性过期

访问时采取判断是否过期(有点类似于延迟加载,对内存不友好,但是大量节省了cpu资源)

定期过期

隔一段时间去扫描一下key(每次扫描一定数量的key,而非全部扫描),这里要注意考虑执行频率和执行

Redis的持久化机制

机制一

RDB(Redis Database)

每隔指定时间,fork一个子进程,将当前数据库快照写入临时文件,写入完成后,再替换原始文件。用二进制方式压缩存储写入磁盘,存的是二进制数据

  • 触发方式
    • 手动触发
      • save命令,使用此命令时,会使主进程处于阻塞状态,直到RDB持久化完成,才会响应其它客户端的命令
      • bgsave命令,fork出一个子进程,父子有一块共享的内存区域,主进程只会在fork时有短暂阻塞,之后就可以响应其它响应
    • 自动触发
      • save m n:是说在m秒内如果有n个键发生改变,则自动触发bgsave
      • flushall: 清空redis的所有数据库,(flushdb,清空当前数据库),同时清空RDB文件,之后生成dump.rdb(内容为空)
      • 主从同步:全量同步时才会触发
RDB优点
  • 只有一个dump.rdb文件,方便持久化
  • 容灾性好,方便备份
  • 性能最大化,fork子进程完成写操作,实现IO最大化
  • 数据集比较大的时候,效率比AOF启动效率/恢复速度要高
RDB缺点
  • 数据安全性低:因为每隔一段时间做一次持久化,如果两次中间redis发生故障,则会有数据丢失
  • fork子进程会占用cpu

机制二

AOF(append only file)

每执行一次增、删、改操作(查操作不会存储),就把该命令追加到log文件中,存的是命令

  • 首先,命令放入AOF缓冲区(不是直接全部写入log)
  • 缓冲区根据同步策略向硬盘进行同步操作
  • 随着AOF文件越来越大,需要对文件进行重写,达到压缩目的
    • 同步策略:
      • 每秒同步:如果两次之间宕机,会丢失一秒的数据
      • 每修改同步:如果宕机会丢失一条数据层
      • 不同步(同步策略我们自己不管,交给操作系统处理) :会丢失较多数据
AOF优点
  • 数据安全(同步策略)
  • 通过append写文件,即使中途宕机了,也不会破坏已存在的内容,redis提供了redis-check-aof工具来解决数据一致性问题
  • 定期rewrite,达到压缩目的
AOF缺点
  • 比RDB文件大,恢复速度慢
  • 数据集大的时候,比RDB启动效率低
    在这里插入图片描述

Redis集群方案(高可用方案)

一 主从复制模式(解决HA单点故障问题)

数据同步且数据全量一致

二 哨兵模式(基于主从模式来的)

主要做分布式协调,选主

  • 集群监控
  • 故障通知
  • 故障转移
  • 配置中心:通知客户端使用新的master地址

三 sharding(分片,分布式缓存寻址)

四 Cluster(分治分片,解决容量、压力、瓶颈问题,哈希槽)

在这里插入图片描述

Redis数据结构及使用场景

在这里插入图片描述

Redis主从复制

  • 全量复制
  • 部分复制
    在这里插入图片描述流程图在这里插入图片描述

布隆过滤器

缓存穿透、缓存击穿、缓存雪崩

缓存穿透

在redis和数据库中都查不到。解决方案:

  • 对参数进行合法性校验
  • 把查不到的结果也放在redis中(比如我们查pro_id=-1的结果是null,那么redis中也存一条对应的记录),但会出现很多冗余无用key的情况,因此这一类缓存数据的有效期要设置的短一点
  • 引入布隆过滤器

缓存击穿

缓存中没有,数据库有(一般针对于热点key)。解决方案:

  • 设置"热点缓存"永不过期,这里注意:在value中有逻辑上的过期时间,然后另起一个线程,定期重建这些缓存
  • 加载DB的时候,防治并发,即在DB往Redis写的时候加一个并发锁

缓存雪崩

缓存大面积同时过期导致请求都被转发到DB。解决方案:

  • 把失效时间分散开(比如在原来统一过期时间基础上加一个随机值
  • 热点数据永不过期

Redis分布式锁的实现

1、setnx+setex(加锁+设置过期时间)

会存在死锁问题如果setnx完成但还没做setex时宕机

2、set(key, value, nx, ex)

将setnx+setex二合一,保证原子性

3、分布式锁可能存在的问题

  • 1、任务超时时,锁会自动释放,导致并发(比如设置的过期时间是5s,但是任务10s还没完成)
    • 解决方法:这里我们可以使用redission(看门狗)进行自动续期来解决
  • 2、加锁和释放锁不是同一个线程操作的(比如过期时间是5秒,任务A执行8s,第5s时锁已释放并紧接着被任务B重新加锁,那么任务A执行完之后在不知道自己超时的情况下它去删除锁,就会出现问题)
    • 解决方法:在value中,存入uuid线程唯一标识,在删除锁的时候判断该标识(使用lua脚本保证原子操作)
  • 3、不可重入,使用redission解决(AQS机制实现的计数器)
  • 4、异步复制的时候可能造成锁丢失,使用redLock红锁机制解决
    • 顺序向5个节点申请加锁
    • 根据一定的超时时间来判断是不是跳过该节点
    • 三个节点加锁成功且花费时间小于锁的有效期
    • 认定为加锁成功

Redis事务的实现

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

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

1、先删缓存再更新数据库。

存在的问题
  -  高并发状态下,线程A删除了缓存、还没写数据库,此时线程B来读发现缓存中没有于是去数据库读,读到的就是旧数据,此时A写完数据库并且更新了缓存,结果B在读到旧数据之后再次更新了缓存,就会出现**脏数据**
解决方案
  - 1 先操作缓存但是不删除,而是把value设置成一个业务上不会用到的值,比如-999。此时B来的时候发现是-999,那么就休眠一会儿再来读
  - 2 `延时双删`。先删除缓存、再写数据库、休眠一会儿再删除缓存  
  • 小结:上面的方案还是会存在问题: 在频繁写时,可能要重复休眠,影响性能
  • 2、先更新数据库再删缓存

    存在的问题
    - 如果数据写完了但是删除缓存失败,会出现数据不一致问题
    
    解决方案
    - 1 设置过期时间(但是本次过期之前,还是会不一致)
    - 2 引入MQ,保证原子操作,以及重试机制
    
    • 小结:也还是会存在问题:只能保证一段时间的最终一致性

Redis如何实现延时队列?

Redis跳表怎么实现?

参考资料:都在问的Redis高频面试题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值