缓存雪崩的解决方案

缓存在同一时间大面积的失效,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力

缓存服务宕机也会导致缓存雪崩现象

解决方法

针对redis服务不可用的情况

  • Redis 集群:采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用
  • 多级缓存

针对大量缓存同时失效的情况

  • 设置随机失效时间:避免大量缓存同时到期
  • 提前预热:针对热点数据提前预热,将其存入缓存中并设置合理的过期时间 (比如秒杀场景下的数据在秒杀结束之前不过期(逻辑过期))。
    • 缓存预热的常见实现方式:定时任务消息队列Kafka可以异步的进行缓存预热

如何保证缓存和数据库中数据的一致性

  • 让缓存失效的时间变短,这样缓存就会很快从数据库从加载数据。(不推荐)
  • 增加缓存更新重试机制:针对缓存不可用导致的缓存删除失败,可以引入消息队列实现异步重试,将删除缓存重试的消息投递到消息队列,然后由专门的消费者来重试,直到成功。

缓存击穿(热点key问题)

请求的 key 对应的是热点数据 ,该数据存在于数据库中,但不存在于缓存中,瞬时大量的请求直接打到了数据库上

举个例子:秒杀进行过程中,缓存中的某个秒杀商品的数据突然过期,这就导致瞬时大量对该商品的请求直接落到数据库上,对数据库造成了巨大的压力

解决方案

  • 提前预热:提前将热点key存入缓存
  • 加锁:在缓存失效之后,通过设置互斥锁确保只有一个请求取查询数据库更新缓存。
  • 永不过期(不推荐)

缓存穿透

大量请求的key 不存在于缓存中,也不存在于数据库中

解决方法

  • 缓存空值
  • 设置布隆过滤器:布隆过滤器可以很方便的判断一个给定数据是否存在于海量数据中。相当于在用户请求和缓存之间添加了一层过滤,将所有可能存在的请求值都存放在布隆过滤器中,当用户请求过来,先判断在不在过滤器中,如果不存在,则直接返回请求参数错误给客户端。

缓存穿透vs缓存击穿

缓存穿透: 请求的key在缓存中不存在,也不存在在数据库中
缓存击穿:请求的key是热点数据,不在缓存中,在数据库中

缓存雪崩vs缓存击穿

缓存雪崩: 缓存中的大量或所有数据失效
缓存击穿: 热点数据不在缓存中(通常是由于缓存中的那份数据已经过期)

解决数据一致性问题常用的缓存读写策略

  • 旁路缓存:
    • 写:先更新数据库,然后直接删除缓存(数据库优先)
    • 读:先读缓存;读不到就读db返回;然后把数据写入缓存
    • 适用于读请求较多的场景
  • 读写穿透
    • 写:先查缓存,缓存中没有直接更新数据库;缓存中存在则先更新缓存,然后缓存同步更新数据库(缓存优先)
    • 读:先读缓存;读不到就读db,写入缓存再返回
  • 异步缓存写入:
    • 类似读写穿透,两者都是由 cache 服务来负责 cache 和 db 的读写。
    • 两者区别在于:读写穿透同步更新数据库和缓存;异步缓存写入只更新缓存,异步批量更新数据库