8问Redis

Redis在项目开发中起着举足轻重的作用,也是互联网公司面试必考的点,下面的灵魂8问,不知道你能答得上来几个?

基础功能

  1. 为什么使用Redis?
  2. 使用Redis有什么缺点?
  3. 单线程的Redis为什么这么快?
  4. Redis的数据类型及使用场景
  5. Redis过期策略和内存淘汰机制?
  6. Redis和数据库双写一致性问题
  7. 如何应对缓存穿透和缓存雪崩问题
  8. 如果解决Redis并发竞争key问题?

为什么使用Redis?

项目中使用Redis,主要考虑性能和并发。

在高并发的情况下,如果所有请求直接打到数据库,数据库连接数会很快用完,出现连接异常。

如果用Redis,可以做一层缓存,请求先访问Redis缓存,缓冲命中的情况下,直接返回了,不需要请求数据库,缓冲未命中才会请求数据库,并把请求结果缓存到Redis,提高了程序的性能和并发。

使用Redis有什么缺点?

使用Redis可以解决高并发问题,但也会引入新的问题。

  • 缓存和数据库双写一致性问题
  • 缓存雪崩问题
  • 缓存击穿问题
  • 缓存的并发竞争问题

单线程的Redis为什么这么快?

单线程工作模型,基于内存

  • 纯内存操作
  • 核心是基于非阻塞的IO多路复用机制
  • C语言实现
  • 单线程,避免了多线程的频繁上下文切换问题,预防了多线程可能产生的竞争问题。

Redis的数据类型及使用场景

String: 存储计数或字符串
Hash: 结构体信息
List: 消息队列
Set: 去重
SortedSet: 排行榜应用

Redis过期策略和内存淘汰机制?

Redis采用的是定期删除+惰性删除策略。

Redis和数据库双写一致性问题

最终一致性和强一致性

redis无法和数据库做到强一致性

最终一致性:

  1. 先删缓存,再更新数据库(客户端可能读到的是旧的数据,因为删完缓存后,还没有写入数据库,但是有新的请求读到了旧的数据,导致缓存里也是旧的数据)
  2. 先更新数据库,再删缓存(更新数据库后,有请求读到了缓存里的旧数据,导致数据不一致,删除缓存后,再读到的数据就是一致的了)
  3. 先删缓存,再更新数据库,再删缓存(同第一步,所以二次删缓存,保证最终一致性)

如何应对缓存穿透和缓存雪崩问题

缓存雪崩

redis服务器意外宕机,导致redis不可用,所有请求打到数据库,数据库连接数上升达到上限,会出现数据库连接异常,影响业务,即使redis恢复,可能redis里没有数据,还是瞬间打满数据库连接,引起缓存雪崩问题。

解决方案:

  1. 事前:Redis建立高可用方案,主从复制+哨兵+集群,保证不会全部出现宕机
  2. 事中:开启限流/降级机制,保证最大连接数不超过数据库承受的连接数
  3. 事后: 开启Redis缓存,保证redis重启后,redis恢复缓存数据

缓存穿透

黑客通过模拟大量不存在的key请求系统,因为在缓存里找不到数据,就会去数据库里查询,也会导致连接数上升,浪费资源

解决方案:

  1. 校验key的合法性(如果用了mongodb的_id,可以校验mongodb的合法性)
  2. 对于不存在的key,即是在数据库里没有查到数据,可以写一个默认值到缓存里并设立TTL,业务上别忘了处理这种情况
  3. 布隆过滤器,优先过滤是否存在key

缓存击穿

高并发中,缓存的key正好失效,导致大量的请求打到数据库

解决方案:

  1. 分布式锁,拿数据的时候锁住,会影响性能
  2. 后台线程在缓存失效前刷新缓存
  3. 如果key数据永不改变,那么把key设置为永不过期

热点数据集中失效问题

解决方案:

  1. 设置key的过期时间时,在基础时间上加一个指定范围的随机数

如果解决Redis并发竞争key问题?

参考: https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-cas.md

  1. 分布式锁,同一时间,只能由一个人来写入,其他人都不允许读和写

高级功能

Redis的线程模型

参考: https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-single-thread-model.md

Redis集群

参考:https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-cluster.md

Redis过期策略

参考:https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/redis-expiration-policies-and-lru.md

Redis高可用/高并发

参考: https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md