面试Redis篇

        本篇主要总结一下面试官可能会在Redis上询问的主要问题。

Redis的使用场景

        问:你的项目中哪些场景中用到了Redis?

        答:根据你的项目回答,一般会在一下几个部分缓存、分布式锁......

缓存

 缓存穿透

        查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查到数据库

  如何解决缓存穿透

        解决方案1:布隆过滤器

          首先解释一下布隆过滤器:它的作用主要是为了判断一个数据是否存在一个集合中,本身是一个数组(单位为bit),只能存放0或1。初始值都为0.

          工作流程:当存储数据时,先通过三次不同的hash算法得到不同的hash值,并在对应hash值数组下标的位置,将0改为1。当查找数据时,通过三次不同的hash算法得到不同的hash值,还是根据hash值找到对应的3个下标,如果都为1,则判断其存在,进行之后的操作。

        整个流程:

         优点:内存占用较少,没有多余的key。

         缺点:实现复杂,存在误判

        解决方案2:缓存空数据(将查询到的空结果进行缓存,一般不使用这个方法)

          优点:实现简单

          缺点:消耗内存,可能会造成数据不一致问题

 缓存击穿

  什么是缓存击穿?

      给某个key设置了过期时间,当key过期的时候,恰好这个时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把DB压垮。

 解决方案

        1.互斥锁:强一致,性能差

        2.逻辑过期:高可用、性能优,不能保证数据的绝对一致

                

 缓存雪崩

  什么是缓存雪崩?

        和缓存击穿相反,指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。

  • 解决方案:
    • 给不同的Key的TTL添加随机值
    • 利用Redis集群提高服务的可用性(哨兵模式、集群模式)
    • 给缓存业务添加降级限流策略(nginx或者spring cloud gateway):降级可做为系统的保底策略,适用于穿透、击穿、雪崩
    • 给业务添加多级缓存(Guava或Caffeine)

双写一致性

  Redis作为缓存,mysql数据如何与Redis进行同步呢(双写一致性)?

  • 双写一致性:当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致
    • 读操作:缓存命中,直接返回;缓存未命中查询数据库,写入缓存,设定超时时间
    • 写操作:延迟双删
      • 删除缓存-->修改数据库--(延时)-->删除缓存
      • 是先删除缓存还是先修改数据库呢
        • 都有问题(缓存和数据库开始都是10)

      • 为什么删除两次缓存
        • 降低脏数据的出现
      • 为什么要延时双删
        • 一般数据库是主从的,需要一定时间让数据库中的数据同步
  • 根据业务给答案
    • 强一致性高的业务解决方案
      • 采用互斥锁
      • 在此基础上可以优化一下(采用Redisson提供的读写锁方式)
        • 这种情况下的放入缓存中的数据一般都是读多写少
        • 共享锁(读锁readLock,加锁之后,其他线程可以共享读操作)
        • 排他锁(独占锁writeLock,加锁之后,阻塞其他线程读写操作)

    • 允许延迟一致的(异步的方案)
      • 利用MQ中间件,更新数据之后,通知缓存删除
      • 基于Canal的异步通知:利用canal中间件,不需要修改业务代码,伪装为mysql的一个从节点,canal通过读取binlog数据更新缓存

持久化

     redis作为缓存,数据的持久化是怎么做的?

  • 两种方式
    • RDB
      • bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB文件
    • RDB(Redis数据备份文件)
      • 人工备份
      • Redis内部有触发RDB的机制,可以在redis.conf文件中找到
    • AOF
      • AOF(默认是关闭的)
      • 在配置中打开

      • AOF重写
        • 针对与某个key的写操作,最后一步才有意义,所以为了减小占有的空间,会采用AOF的重写

对比

 数据过期策略

        两种删除策略

        惰性删除:设置该key过期时间后,我们不去管他,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key。

        优点:对CPU比较友好,很多用不到的key不用浪费时间进行过期检查

        缺点:对内存不友好,很多已过期的key因为没有使用到而导致一直占用内存空间,内存永不释放

        定期删除:每隔一段时间,我们就对一些key进行检查,删除里面过期的key(从一定数量的数据库中取出一定数量的随机key进行检查)

        定期删除的两种模式

  • SLOW模式(慢)
  • FAST模式(快)

         优点:可以通过限制删除操作执行的频率和时长减少对CPU的影响,另外也能有效过期key占用的内存。

        缺点:难以确定删除操作的时长和频率额

        Redis的删除策略:惰性删除+定期删除两种策略进行配合使用

数据淘汰策略

        8中淘汰策略

noeviction:不淘汰任何key,但是当缓存满的时候就不允许写入新的数据,默认就是这种策略

volatile-ttl:对设置了任何TTL的key,比较key的剩余TTL值,TTL越小,删除优先级越高

allkeys-random:对全体key进行随即淘汰。

volatile-random:对设置了TTL的key进行随即淘汰。

allkeys-lru:对所有的key,基于LRU算法进行淘汰。

volatile-lru:对设置了TTL的key,基于LRU算法进行淘汰。

allkeys-lfu:对所有的key,基于LFU算法进行淘汰。

volatile-lfu:对设置了TTL的key,基于LFU算法进行淘汰。

LRU算法

        最近最少使用,用当前时间减去最后一次访问的时间,这个值越大淘汰的优先级越高。

LFU算法

        最少频率使用,统计每个key的访问频率,值越小的淘汰优先级越高

分布式锁

使用场景

        通常情况下:集群情况下的定时任务、抢单、幂等性场景

        举例抢卷场景:

        正常情况:

         特殊情况:

解决方案:互斥锁,在查询剩余库存前,先获取互斥锁,如果获取就正常进行,如果没获取到就一直等待

但是服务往往是集群部署,每个进程的都有一个锁,这时就要用到分布式锁

实现原理

        Redis实现分布式锁主要利用Redis的setnx命令。setnx是SET if not exists(如果不存在,则SET)的简写。设置失效时间是为了在服务宕机后,依然可以释放锁,避免造成死锁

        Redis实现分布式锁如何控制锁的有效时长:

  • 根据业务执行时间预估
  • 给锁续期
    • 我们自己实现很麻烦,市面上已经有成熟的技术了

redisson实现的分布式锁-执行流程(看门狗机制)

这个看门狗会每隔一段时间给锁续期

  • redissson实现的分布式锁能解决主从一致性吗?
    • 若主节点宕机

    • 会在从节点中选出一个当主节点(哨兵模式)
    • 这时出现两个线程同时拥有同1把锁
    • Redisson提供红锁来解决主从一致性的问题
      • 但是实现复杂,性能差,运维繁琐
    • 保证强一致性
      • CP思想:zookeeper实现的分布式锁

其他

Reids集群有哪些方案?

        主从同步、哨兵模式、分片集群

介绍一下主从同步:

        单节点Redis的并发能力是有上限的,要更进一步提供Redis的并发能力,就需要搭建主从集群,实现读写分离。

主从数据同步的原理:

        

  • 主从全量同步
    • 新概念
    • 是第一次吗?
      • 根据relid判断,replid不同,是,正常进行
      • 不是,返回主节点的replid、offeset,根据offset从节点更新信息
  • 主从增量同步(slave重启或者后期数据变化)

怎么保证Reids的高并发高可用

        Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复(监控、自动故障恢复、通知)。哨兵的结构和作用如下:

        监控:Sentinel会不断检查你的master和slave是否按预期工作。

        自动故障恢复:如果master故障,Sentinel会将一个slave提升为master,故障恢复后也会是以新的master为主

        通知:当集群发送故障时,会将最新消息推送给Redis客户端。

Redis分片集群有什么作用?

        分片集群主要解决海量数据的存储问题:集群中有多个master,每个master中保存着不同的数据。并且给每个master设置多个slave节点,增大集群的高并发能力,同时每个master可以通过ping来互相检测彼此的健康状态,当客户请求访问到任意节点就会转发到正确的节点

分片集群中是怎么存储数据和读取的?

        

  • Redis分片集群引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。

redis是单线程,为什么还这么快

1.redis纯内存操作,执行速度很快

2.采用单线程避免上下文的切换

3.采用多路I/O复用模型,非阻塞IO

解释一下I/O多路复用模型

        用单个线程监听多个socket,并在某个socket可读、可写时得到通知,避免无效的等待。充分利用CPU资源。该模型目前基本采用epoll模式实现。通知用户Socker进程就绪的同时,将已就绪的Socket写入到用户空间中。提高了性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奈奈朵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值