redis面试题:缓存穿透,雪崩,击穿,保证redis跟数据库的数据一致性,主从复制原理以及流程,哨兵模式原理以及流程,集群化模式原理以及流程

缓存穿透,雪崩,击穿:

redis的缓存穿透:
        指的是前端发过来的数据在redis和数据库中都不存在,如果重复接收大量这样的请求,会造成性能浪费。
解决的方案有两个:
1.缓存空对象,并添加过期时间,这样实现起来比较简单,维护方便,但是会有额外的内存损耗,还有可能造成数据短期的不一致(比如说缓存一个id为1的假数据,这个数据不是真实存在的,但是后面真实添加了一个id为1的数据,这样就会造成数据的不一致性)

2.使用博隆过滤器,它的内存占用较小,但是实现比较复杂,还存在误判的可能
 

缓存雪崩:

        是指在同一时间内大量的缓存key同时失效或者redis服务宕机,导致大量请求直接访问数据库,给数据库带来很大的压力
        解决方法:给不同的key添加不同的过期时间,然后搭建redis集群,给业务添加多级缓存或者进行流量的限流

 

缓存击穿:

        指的是一个被高并发访问并且缓存的重建业务比较复杂的key突然失效,大量的请求会在瞬间给数据库带来很大的压力

解决方法:

        互斥锁原理:
                如果查询的缓存数据不存在,那就先获取互斥锁,然后查询数据库把查到的数据写入缓存并释放互斥锁,比如线程A是一个查询请求,查询的数据在缓存中没有,那就先获取互斥锁,然后查询数据库,在没有写入缓存并且没释放锁的情况下,线程B进来了,线程B也是查询请求,查询的数据在缓存中没有,就会获取互斥锁,但是获取互斥锁的时候会失败,因为线程A还没释放锁,然后等待一段时间会再次查询缓存,假设线程A已经写入缓存成功,那么线程B就会查询缓存成功,返回数据,否则一样会进行重试

        逻辑过期原理:
                比如线程A发现该缓存的物理过期时间已经到了,那么就会获取互斥锁,然后开启一个新的线程B,把缓存重构的工作交给线程B执行,然后线程A就直接返回旧的缓存数据,当线程B还没有写入新的缓存数据并且释放锁的时候,线程C来了,线程C发现缓存的数据还是过期的,并且获取锁失败,就表示有线程在执行缓存的重构了,然后就直接返回旧数据,当线程B重构缓存数据成功后就会释放锁

保证redis跟数据库的数据一致性:

redis的数据更新:要先操作数据库,再删除缓存,然后加缓存过期时间来兜底

1.如果先删缓存在操作数据库会导致的问题:
正常情况:
        线程A把缓存删了,然后更新数据库,更新完毕之后,线程B查询缓存中的数据,发现缓存中没有数据库,然后去读取数据库,这个时候读取的数据是更新之后的数据,然后把数据写入到缓存中
 

异常情况:
        线程A先把缓存删掉了,然后准备更新数据库的时候,线程B进来了,线程B是一个查询请求,先查询缓存数据,发现缓存中没有数据然后就读取数据库,把读取到的数据写入到缓存中,然后线程B执行完毕后,线程A才更新数据库完毕,这样会导致数据的不一致,这种情况发生的概率还是很大的,因为在一般情况下reids是比数据库快的,所以在并发情况下,这种策略发生错误的情况就比较大

2.先操作数据库,然后再删除缓存:
正常情况:
        线程A更新完成数据库后,把缓存删了,然后线程B进来了,线程B是一个查询请求,查询到缓存中没有数据之后,会读取更新之后的数据写入缓存
 

异常情况:
        线程A是一个查询请求,假设缓存中是没有数据的,那么线程A在查询缓存之后会去查询数据库然后再把数据写入到缓存中,在写入缓存数据的时候,线程B进来更新数据库,更新完毕之后线程A的写缓存操作才完成,这个时候就会导致数据不一致,但是这种情况发生的概率是很小的,因为首先要多个线程并发执行,然后还要缓存中没有数据,而且还要保证更新数据库的操作比写入缓存的操作要块,但是在一般情况下,redis的速度都是比数据库要快的,所以这种情况发生的概率会比较小

但是以上两种情况都会导致数据不一致,所以在添加缓存数据的时候,要给缓存数据加个过期时间,这样才能确保最终数据的一致性

数据类型:

        redis有string,list,hashmap,set,zset五种常有的数据结构

主从复制:

        一个主节点,多个从节点,主节点可以进行读写操作,从节点只能负责读操作,当主节点上执行写命令的时候,会把数据同步到从节点上,当读取数据的时候,去从节点上进行读取,这样就可以分担主节点的读压力,配置主从复制的操作是在从节点上,使用slaveof命令,然后跟上主节点的ip和端口号

主从原理:

        当主从服务器连接的时候,先进行全量同步,如果从节点重新连接之后会进行增量同步。

全量同步流程

        当从节点连接到主节点后,会发送psync命令,主节点接psync命令之后,执行bgsave命令生成RDB快照文件并使用缓存区来记录此后执行的所有写命令,当bgsave命令完成之后,会向所有的从节点发送RDB快照文件,从节点收到RDB快照文件后,会把文件写入硬盘,然后清空所有旧数据,再从本地硬盘载入收到的快照文件到内存中(同时基于旧的数据版本对外提供服务),主节点发送RDB快照文件之后,继续向从节点发送缓冲区中的写命令,然后从节点接收并执行命令。

增量同步

        当从节点重新连接之后,会发送自己的replid跟offset,主节点接收到之后,会根据offset来获取之后的数据,然后再发送给从节点,从节点接收到之后就开始同步

哨兵模式:

        哨兵模式是主从复制的改良版,因为主从模式的主节点挂了之后,需要手动去把从节点变成到主节点,而且在这段时间内,只能进行读操作,这种模式效率比较低,所以就加入哨兵去监听主从服务器,发现主节点宕机之后,会自动把从节点变成主节点,然后通过发布订阅模式通知其他服务器,修改配置文件,更换主机。而且哨兵之间还可以做集群,用来防止一个哨兵挂了就无法维持哨兵模式。

哨兵模式原理:

哨兵模式有三个定时任务:

        1.每10S向主节点发送请求,获取最新的所有从节点信息
        2.每2s广播当前哨兵对于主节点的判断,以及当前哨兵节点的信息,这里广播是通过redis的发布订阅模式来实现的
       3.每1s会向主从节点和其他哨兵发送ping命令,进行心跳检测。

        假设主节点宕机,哨兵1先检测到这个结果,但是哨兵1并不会立马进行故障切换操作,而是主观的认为主节点不可用,当其他的哨兵也检测到主节点不可用,并且数量达到一定值的时候,哨兵之间就会进行一次投票,投票的结果会选出一个哨兵代表,由哨兵的代表进行故障切换操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监听的从节点切换主机,这个过程称为客观下线。如果有多个哨兵,不仅每个哨兵会监听主从节点,而且哨兵之间也会互相监听

集群化模式:

        无论是主从还是哨兵模式,其中的从节点还是保存了全部的数据,这样是比较浪费内存空间的,而且当内存的数据量太大的时候,redis的写操作性能会受到影响,再加上哨兵或者主从模式下的的写操作是单机模式,会受到单机性能影响,所以就出现了集群化模式。

       原理:redis 集群中内置了 16384 个哈希槽,当需往 Redis 集群中执行一个写命令时,redis 先对 key 进行一个算法处理,然后再把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据主节点的数量,均等的将哈希槽映射到不同的主节点上,从而达到集群化的效果

猜你喜欢

转载自blog.csdn.net/qq_26112725/article/details/129516800