Redis常见面试题

Redis基本数据结构类型

  • StringSDS动态字符串结构,最大存储512M,常用于共享 session、分布式锁,计数器、限流
  • Hash:k-v结构,常用于缓存用户信息
  • List:list,常用于消息队列,文章列表
  • Set:set,常用于用户标签,生成随机数抽奖、社交需求(点赞)
  • Zset:已排序字符串集合,常用于:排行榜,社交需求(点赞)

    特殊数据结构类型:1. Geospatial(地理位置) 2. Hyperloglog(基数统计算法) 3. Bitmap(以比特位为单位的数组)


Redis为什么这么快

  • 基于内存实现
  • 高效的数据结构
  • 合理的数据编码:动态字符串、双端链表、压缩链表、字典、跳跃表
  • 合理的线程模型:单线程模型和I/O 多路复用
  • 虚拟内存机制

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

缓存击穿

原理:热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key 有大量的并发请求过来,从而大量的请求打到数据库
解决方案

  • 使用互斥锁:比如redis的setnx去set一个mutex key,当操作返回成功时(分布式锁),在查数据库,并回设缓存,最后删除mutex key,当操作返回失败,证明有线程在查询数据库,当前线程睡眠一段时间在重试整个get缓存的方法
  • 设置热点数据:不设置过期时间或根据业务设置较长的过期时间,快要过期时,异步线程去更新和设置过期时间

缓存穿透

原理:读请求访问时,缓存和数据库都没有某个值,这样就会导致每次对
这个值的查询请求都会穿透到数据库,这就是缓存穿透
解决方案

  • 使用布隆过滤器先判断这个值是否存在,存在再执行查询
  • 缓存空的对象,数据库未查到数据时,返回一个空对象,并缓存起来设置过期时间,后面的请求进来直接访问这个空对象

缓存雪崩

原理:缓存中数据大批量到过期时间,而查询数据量巨大,请求都直接访问数据库,引起数据库压力过大甚至down机

解决方案

  • 构建多级缓存,nginx缓存+redis缓存+其他缓存(ehcache等)
  • 使用锁或队列,保证不会有大量的线程对数据库进行读写
  • 搭建redis集群,做成高可用,主备、异地多活
  • 数据预热,上线前预先访问一次,提前加载缓存,手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀
  • 限流降级,缓存失效时,通过锁的方式来限制访问数据的顺序,优先给主业务服务

Redis缓存和Mysql数据库双写,如何保证一致性

对于时效性要求不高,更新频率比较低的业务
采用设置缓存过期时间的方式,简单方便,缺点就是在缓存即将过期的时候可能会有数据不一致的问题

对于时效性和一致性要求比较高的业务
采用同步双写的方式处理,在更新数据的同时去更新缓存,通常说的缓存和数据一致性的问题,通常也是在这种场景下讨的,比较稳妥的方式就是延时双删的方法,先删除缓存,然后更新数据库过一会儿再次进行缓存的删除,一会儿这个时间需要大于写一次缓存的时间,来保证数据库和缓的一致性。再稳妥一点的话,还需要保证删除缓存的操作确定被执行,可以增加消息列,对该操作失败后进行失败重试的方式来保证删除缓存操作被执行。

对于时效性要求一般,但是需要同步数据到多个服务的业务
采用相关的服务监听,修改数据库时发消息通知,根据通知修改缓存数据。