Redis常见面试题总结


1. AOF 与 RDB 的区别?

  AOF:redis会将每一个请求都记录在日志文件中,当redis重启时,会读取日志文件,将请求重新执行一遍,以恢复数据到最新状态,aof默认关闭,通过appendonly yes开启
  aof有三种策略:1)aof always:每一条请求都会写入日志,这样会保证数据不丢失,但是会影响redis的效率
  2)aof everysec:每秒将请求写入日志一次,对redis性能影响较小,但是redis宕机的时候会丢失一秒的数据
  3)aof sync:redis定时将请求写入日志,默认一分钟,对性能几乎无影响,但是会丢失数据比较多
  aof重写:配置aof重写策略,当aof日志文件增长一定大小时,redis将会fork一个子进程重写日志文件,将文件保留可以恢复最新数据的最小大小
  优点:1)开启aof always时,可以保证数据不丢失,及时是aof everysec,也只会丢失一秒数据
    2)即使断电,也可以通过工具修复日志
    3)写入错误的redis命令时,可以通过删除错误命令,执行aof日志命令恢复数据
  缺点:对性能影响比RDB大,恢复速度较慢

  RDB:redis会定期保存数据快照到rdb文件中,当redis重启时,读取数据快照恢复数据,默认开启rdb策略
  通过 sava [second] [changes] 来配置rdb快照策略,可以配置多条来实行多级快照保存策略,可以通过BGSAVE来手动处罚rdb快照保存
  rdb会在保存时,fork一个进程来将数据写入临时文件,当写入完毕时,用临时文件替换上次持久化文件,对redis几乎无影响,比aof高效,但是最后一次的数据会丢失
  优点:1)由于是通过fork子进程来操作,对redis影响很小
    2)恢复文件的速度比aof快
    3)每次快照会保存完整的数据快照,可以作为灾备手段
  缺点:1)会丢失最后一次的数据
    2)当数据较多时,cpu不给力,子进程执行快照会耗时较长,影响redis对外服务能力

  推荐使用rdb + aof everysec组合的持久化方式

2. Redis集群有哪几种?
  1)主从模式:一个master,多个slave,支持主从复制,支持读写分离
    优点:slave可以分担master的读压力,master挂了后,slave依然可读
    缺点:master挂了之后,slave不会选举出新master,难以扩容,不推荐使用这个模式
  2)哨兵模式:通过哨兵来监控master和slave,master挂了之后会选举出slave
    优点:继承主从模式的优点,并且更加健壮,可用性更高
    缺点:同样难以扩容
  3)集群模式:redis3.0之后支持redis集群,可以在多台机器上部署多台master(每个master存储一部分数据),每个master有多个slave,当某个master挂了后,redis cluster会从slave中选举出新master

3. Redis选举流程?
  1)Redis的某个slave节点发现自己的主节点变为FAIL状态时,会尝试选举成为新的master节点(持有最新数据的slave节点会首先发起选举)
  2)该slave节点会广播一条消息给其他master节点
  3)其他master节点接收消息之后,会判断请求者的合法性,若合法,会发送确认消息给该slave节点(若其他master节点未接到要求选举slave节点的master节点的FAIL消息,会拒绝投票)
  4)当slave节点收到超过半数的选票之后,会成为master节点,若选举失败,会开始下一轮选举
  5)新的master节点会继承原master节点的hash槽
  6)新的master节点会广播消息告诉其他节点自己成为了master节点
  7)新master节点开始处理槽相关的请求

4. Redis Cluster数据分片?
  Redis Cluster通过hash槽分片存储数据,共有16384个hash槽,每个节点拥有一部分hash槽,key通过CRC16算法来确认hash值,映射到相应的节点上
如果增加节点,会从现有节点分配hash槽到新节点,如果删除节点,会将删除节点的hash槽分配给剩余节点
Redis Cluster没有自己实现hash槽的分配与计算,需要客户端自己实现,客户端可以根据机器CPU能力来分配hash槽区间大小

5. 了解一致性hash吗? 为什么不用一致性hash?
  一致性hash是将节点映射在一个2^32大小的圆环上,key通过hash,得到在圆环上单的位置,数据存储在顺时针的下一个节点上,
当节点有变更时,知会影响节点与下一个节点间的数据。
  为什么不用:实际情况中节点一般较少,一致性hash当节点较少时,会出现数据倾斜,数据分布不均匀,
而且节点少时,当节点出现变化情况下,节点中的数据映射影响很大。

6. Redis如何保证slots迁移过程中的数据正常读写
  当节点A的数据迁移到节点B中时,会将节点A标记为Migrating(迁移)状态,将节点B标记为importing(导入中)状态,节点的槽映射不做修改
当有数据访问节点A时,如果数据还在节点A上,会直接返回数据,如果不存在,返回一个ACK转向消息
客户端收到ACK消息,转而访问转向所指定节点B,先发送一个ACKING请求,再发送真正的请求
客户端收到节点B返回的数据后,不会改变槽映射关系
等待节点A所有slots都迁移到节点B后,再次有请求访问节点A,会返回一个MOVED消息,将映射永久指向节点B

7. Redis 是什么实现主从同步的?怎么保证数据一致性?
  Redis master节点可以执行读写命令,slave节点只能执行读命令,主从同步分为三种
  1)初次全量复制
  当一个slave节点启动时,会向master节点发送sync命令,master节点接收命令后开始执行bgsva,保存rdb快照,将rdb快照发送给slave节点,
并将同步期间的写命令缓存起来,slave节点接收rdb快照后,载入数据,然后master节点会发送缓存的写命令,slave节点执行缓存的写命令。
  2)命令传播
  master节点每次执行写命令后,会将命令发送给slave节点,slave节点执行命令进行同步
  3)重新复制
  当slave节点断开连接重连后,会发送偏移量给master节点,master节点首先会判断该slave节点是否之前是自己的从节点,如果不是,进行全量复制
如果是,会比较和自己的偏移量,如果不一致,会从积压缓冲区将偏移量之后的命令发送给slave,slave执行命令进行同步

8. Redis 的过期策略都有哪些?Redis 怎么删除过期数据的?
  定时删除:在给key设置过期时间的同时,给key加一个定时器,当key过期的时候删除它
    优点:可以及时删除key,保证内存释放
    缺点:消耗性能,每个设置过期的key都需要一个定时器
  惰性删除:当取到过期key的时候,删除key,返回null
    优点:对性能无影响
    缺点:当过期key长时间没有被取时,会发生内存泄露
  定期删除:固定频率去删除过期的key
    优点:在内存处理方面优于惰性删除,在cpu处理方面优于定时删除
    缺点:并不会检查所有的key是否过期,而是随机选择一部分key,可能存在很多key过期没有被删除
  Redis采用定期删除+惰性删除的策略

9. Redis内存淘汰策略?
  noeviction:内存不足时,新写入操作会报错
  allkeys lru:内存不足时,移除所有key中最近最少使用的(推荐使用)
  volatile lru:内存不足时,移除设置了过期时间的key中,最近最少使用的(当redis又当缓存,又当持久层时使用)
  allkeys random:内存不足时,在所有key中随机移除一个
  volatile random:内存不足时,在设置了过期时间的key中随机移除一个
  volatile ttl:内存不足时,在设置了过期时间的key中,移除剩余过期时间最短的key

10. 热点Key问题的怎么发现与解决?
  如何发现:
  1)凭借业务经验,提前预估热key
  2)在客户端进行收集,在操作redis前,加一行代码进行统计
  3)用proxy层进行收集,不是所有项目的redis架构都有proxy层
  4)自己写程序抓包分析,开发成本高,维护苦难,容易丢包
  5)用redis自带命令:monitors命令和hotkeys命令,会影响redis性能
如何解决:
  1)利用二级缓存
    发现之后,利用jvm做二级缓存,将热key存在hashmap中,后面的请求都从hashmap中取
  2)备份热key
    将热key备份到多个redis节点中,请求过来的时候分散到多个节点去取

11. 为啥 Redis 单线程模型也能效率这么高? 
  读110000tps,写81000tps
  原因:1、单线程操作,避免了上下文的切换;
    2、纯内存操作,减少IO
    3、使用了非阻塞多路复用IO模型:Redis client根据不同操作产生不同的soket,redis服务端有一段IO多路复用程序,将soket置入队列中,
然后文件事件分派器依次从队列中取,分发给不同的事件处理器处理

12. 什么是缓存穿透和雪崩,如何解决缓存穿透和雪崩? 
  缓存穿透是:用户请求了一个在数据库中不存在的数据,导致缓存层失效,请求直接打到数据库,并发量大的情况下会打垮数据库
  解决:1、当查询数据库不存在时,给这条数据设置一条空值的缓存,避免后续请求都打到数据库;
    2、使用布隆过滤器实现,布隆过滤器内部通过一个bitmap,将所有存在的key都存在map中,每次请求都查找map中是否存在key,不存在则查看
  缓存击穿:缓存设置了过期时间,在过期时间失效的一刻,恰好大量请求打过来,由于新的请求还来不及写入缓存,导致所有请求打到数据库,进而打垮数据库
  解决:1、将热点数据设为永不失效
    2、给请求数据库的操作加锁,单机用synchronized或ReentrantLock,分布式集群环境可以用redis做分布式锁
  缓存雪崩:在同一时刻,大量缓存集中失效,导致大量请求直接打到数据库,使数据库被打垮
  解决:给key设置过期时间的时候加上随机数,使过期时间随机分布


13. 怎么高效的批量删除 Redis上面的 KEY ?
  redis本身不提供批量删除功能,可以通过keys、scan加xargs组合命来来实现批量删除
  1)redis-cli -h xxx.xxx.xxx -p xxxx --raw keys "ops-coffee-*" | xargs redis-cli del
    会导致redis阻塞,不推荐使用
  2)redis-cli -h xxx.xxx.xxx -p xxxx --scan --pattern "*-coffee-*" | xargs -L 2000 redis-cli del
    scan渐进式删除,会将操作分批执行,不会阻塞redis