MST

星途 面试题库

面试题:Redis与MySQL读写分离缓存模式下的缓存穿透、缓存雪崩和缓存击穿及优化策略

请深入分析Redis与MySQL读写分离缓存模式下,缓存穿透、缓存雪崩和缓存击穿这三种问题产生的原因,并分别提出至少两种不同层面(如架构设计、代码实现、运维等)的优化策略,同时说明优化策略的原理和适用场景。
19.9万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

缓存穿透

  1. 产生原因
    • 恶意请求:大量请求查询数据库中不存在的数据,由于缓存中也没有,导致请求直接穿透到数据库。
    • 缓存失效:在某些情况下,可能缓存数据没有正确设置,或者缓存过期清理后没有及时重新填充,使得不存在的数据查询直接到数据库。
  2. 优化策略
    • 架构设计层面
      • 布隆过滤器
        • 原理:布隆过滤器是一个很长的二进制向量和一系列随机映射函数。当一个元素被加入集合时,通过多个哈希函数将其映射到布隆过滤器的不同位置,将这些位置设为1。查询时,元素通过同样的哈希函数映射,若对应位置不全为1,则元素一定不存在;若全为1,则元素可能存在。这样可以在缓存之前过滤掉一定不存在的数据,避免查询穿透到数据库。
        • 适用场景:适用于数据量较大且可以预估的场景,例如电商商品ID查询等,能有效减少无效查询对数据库的压力。
    • 代码实现层面
      • 空值缓存
        • 原理:当查询数据库发现数据不存在时,在缓存中设置一个空值(例如null)并设置较短的过期时间。后续相同的查询先命中缓存中的空值,避免再次查询数据库。
        • 适用场景:适用于偶尔出现查询不存在数据的场景,简单易实现,但不适用于大量不存在数据的查询场景,因为会占用一定的缓存空间。
    • 运维层面
      • IP访问限制
        • 原理:通过分析请求来源,对频繁发送异常请求(大量查询不存在数据)的IP进行限制,例如封禁一段时间。
        • 适用场景:主要针对恶意攻击导致的缓存穿透,能在一定程度上保护数据库免受恶意请求的影响。

缓存雪崩

  1. 产生原因
    • 大量缓存同时过期:如果设置了大量缓存数据具有相同或相近的过期时间,当这些缓存同时过期时,大量请求会直接打到数据库,导致数据库压力瞬间增大,甚至可能使数据库崩溃。
    • 缓存服务故障:例如Redis集群中的某个节点故障,可能导致大量缓存数据无法访问,请求全部转向数据库。
  2. 优化策略
    • 架构设计层面
      • 分散过期时间
        • 原理:在设置缓存过期时间时,给每个缓存数据加上一个随机的时间偏移量,使缓存过期时间尽量分散,避免大量缓存同时过期。
        • 适用场景:适用于所有使用缓存的场景,简单有效,能降低缓存雪崩发生的概率。
      • 多级缓存架构
        • 原理:构建多级缓存,例如一级缓存使用Redis,二级缓存可以使用本地缓存(如Guava Cache)。当一级缓存失效时,先从二级缓存获取数据,若二级缓存也没有,再查询数据库。这样可以在一定程度上缓解数据库压力。
        • 适用场景:适用于对性能要求较高且允许一定数据不一致的场景,通过多级缓存的层次结构来分散请求压力。
    • 代码实现层面
      • 缓存更新策略优化
        • 原理:在缓存数据过期前,提前进行异步更新,确保缓存数据的连续性。例如在缓存过期前10%的时间内,启动一个异步任务去更新缓存数据。
        • 适用场景:适用于对数据实时性要求较高的场景,能在不影响业务使用缓存的情况下,保证缓存数据的有效性。
    • 运维层面
      • 缓存高可用
        • 原理:通过搭建Redis集群,采用主从复制、哨兵模式或Cluster模式,保证缓存服务的高可用性。当某个节点故障时,其他节点可以继续提供服务,减少因缓存服务故障导致的缓存雪崩风险。
        • 适用场景:所有依赖缓存的应用场景,通过提升缓存服务的可靠性来防止缓存雪崩。

缓存击穿

  1. 产生原因
    • 热点数据过期:某个热点数据在缓存中过期的瞬间,大量并发请求同时查询该数据,由于缓存中没有,这些请求会同时穿透到数据库,给数据库造成巨大压力。
  2. 优化策略
    • 架构设计层面
      • 互斥锁
        • 原理:在查询缓存未命中时,先获取一个分布式锁(例如使用Redis的SETNX命令实现),只有获取到锁的请求才能查询数据库并更新缓存,其他请求等待。获取锁的请求更新完缓存后释放锁,其他等待的请求再次查询缓存即可命中。
        • 适用场景:适用于对一致性要求较高的热点数据场景,通过加锁机制保证同一时间只有一个请求查询数据库,避免数据库压力过大。
    • 代码实现层面
      • 逻辑过期
        • 原理:在缓存数据中设置一个逻辑过期时间,实际缓存数据不过期。当查询缓存数据时,发现逻辑过期,使用一个后台线程去更新缓存数据,前台请求直接返回旧数据。这样可以保证请求不会直接穿透到数据库,同时在一定程度上保证数据的实时性。
        • 适用场景:适用于对数据一致性要求不是特别高,但对性能要求较高的热点数据场景,通过逻辑过期和后台更新机制减少对数据库的查询。
    • 运维层面
      • 热点数据持久化
        • 原理:对于热点数据,设置其不过期,或者采用定期更新的方式保证其有效性,避免因过期导致的缓存击穿。
        • 适用场景:适用于热点数据明确且数量有限的场景,通过对热点数据特殊处理,确保其始终在缓存中,减少对数据库的冲击。