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的速度都是比数据库要快的,所以这种情况发生的概率会比较小

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

主从复制:

        一个主节点,多个从节点,主节点可以进行读写操作,从节点只能负责读操作,当主节点上执行写命令的时候,会把数据同步到从节点上,当读取数据的时候,去从节点上进行读取,这样就可以分担主节点的读压力,配置主从复制的操作是在从节点上,使用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 会根据主节点的数量,均等的将哈希槽映射到不同的主节点上,从而达到集群化的效果

常见数据类型以及场景

string,list,hash,set,zset ,基数统计,位图,地理位置

        string就不用说了,这个是使用最多的

        list:我用List来保存用户的文章列表,粉丝列表的这种类型的数据

        hash是比较常用的,可以用来存用户一些基本数据,虽然string也可以实现,但是string要事先把数据格式化成为json字符串,要用的时候就取出来再转成对象,这样就比较麻烦,所以用hash会比较好很多

        set通常用来做取交集,去重这些操作

        zset是有序不重复集合,这个用得很少

        基数统计也是可以用来做取交集,还有在一些大数据里面去重

        位图通常来做只有两种状态的需求,比如打卡,未打卡,上班,下班这些需求      

        地理位置,这个没用过

底层的数据结构:如果string存的是数字,那底层用的就是int类型,要是字符串的话,那就是sds动态字符串,list底层用双向链表,hash,set,zset底层都有用到字典

事务

        首先redis的每一个操作都是原子性的,如果有的需求是要多条redis命令都操作成功,才算需求完成,那这个时候就需要事务的机制了,事务主要有四个命令:事务开始,事务提交,事务撤销,事务监听

        事务主要有3个特点:会按照命令入队的顺序来执行代码,然后不会受到其他客户端的请求影响,而且事务不能嵌套

        事务监听:在事务开启之前可以监听一个或者多个key,如果在开启事务之后,至少有一个key对应的value值被修改了,那在执行事务提交的时候就会失败,会执行事务取消的操作,底层主要是使用cas乐观锁来实现的

        redis事务回滚:主要是分为两种,一种是编程时错误,例如语法错误,那这个时候,已经执行了命令的代码,也会进行回滚,如果是运行时错误,例如参数错误,那执行命令的代码,是不会进行回滚的

看门狗

        看门狗是redission提供的一种机制,主要是用于分布式锁的自动续期的,如果执行业务代码的时间大于锁的过期时间,那么会自动续期,否则的话有可能会造成锁的错误释放,以及数据混乱
        在调用lock方法的时候,不传递参数就默认开启看门狗机制,然后默认过期时间为30秒,看门狗主要是通过lua脚本去实现

持久化

        有RDB和AOF

        rdb模式是默认模式,可以在指定的时间间隔内生成数据快照文件 ,默认保存到dump.rdb文件中。当redis重启后会自动加载dump.rdb文件中内容到内存中。可以使用SAVE (同步)或BGSAVE (异步)手动保存数据。

        使用同步命令的话,只要在规定时间内,有执行过n次修改的话,这个n的值是自己设置的,就会自动执行bgsave命令。

        使用rdb模式,可以比较方便的进行数据持久化以及数据恢复,而且数据备份会由一个子进程进行,不影响父进程做其他事情,但如果在两次快照间隔之间redis宕机了,那么两次间隔内的数据就没有了,而且当备份的数据量比较大,性能会有影响。

        AOF模式要在redis.config文件里面开启,Redis支持AOF和RDB同时生效,如果同时存在,AOF优先级高于RDB ( Redis重新启动时会使用AOF进行数据恢复),AOF会监听要执行的命令, 如果发现执行的命令有修改操作,那么会直接把命令同步到日志里面, 这样就可以防止Redis突然宕机造成的数据丢失,所以AOF模式比rdb模式会更加安全,但是要处理的数据量会大于RDB,在速度上也会比RDB慢一点

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值