面试题答案
一键面试缓存穿透
- 产生原因:
- 恶意请求:大量请求查询数据库中不存在的数据,由于缓存中也没有,导致请求直接穿透到数据库。
- 缓存失效:在某些情况下,可能缓存数据没有正确设置,或者缓存过期清理后没有及时重新填充,使得不存在的数据查询直接到数据库。
- 优化策略:
- 架构设计层面:
- 布隆过滤器:
- 原理:布隆过滤器是一个很长的二进制向量和一系列随机映射函数。当一个元素被加入集合时,通过多个哈希函数将其映射到布隆过滤器的不同位置,将这些位置设为1。查询时,元素通过同样的哈希函数映射,若对应位置不全为1,则元素一定不存在;若全为1,则元素可能存在。这样可以在缓存之前过滤掉一定不存在的数据,避免查询穿透到数据库。
- 适用场景:适用于数据量较大且可以预估的场景,例如电商商品ID查询等,能有效减少无效查询对数据库的压力。
- 布隆过滤器:
- 代码实现层面:
- 空值缓存:
- 原理:当查询数据库发现数据不存在时,在缓存中设置一个空值(例如null)并设置较短的过期时间。后续相同的查询先命中缓存中的空值,避免再次查询数据库。
- 适用场景:适用于偶尔出现查询不存在数据的场景,简单易实现,但不适用于大量不存在数据的查询场景,因为会占用一定的缓存空间。
- 空值缓存:
- 运维层面:
- IP访问限制:
- 原理:通过分析请求来源,对频繁发送异常请求(大量查询不存在数据)的IP进行限制,例如封禁一段时间。
- 适用场景:主要针对恶意攻击导致的缓存穿透,能在一定程度上保护数据库免受恶意请求的影响。
- IP访问限制:
- 架构设计层面:
缓存雪崩
- 产生原因:
- 大量缓存同时过期:如果设置了大量缓存数据具有相同或相近的过期时间,当这些缓存同时过期时,大量请求会直接打到数据库,导致数据库压力瞬间增大,甚至可能使数据库崩溃。
- 缓存服务故障:例如Redis集群中的某个节点故障,可能导致大量缓存数据无法访问,请求全部转向数据库。
- 优化策略:
- 架构设计层面:
- 分散过期时间:
- 原理:在设置缓存过期时间时,给每个缓存数据加上一个随机的时间偏移量,使缓存过期时间尽量分散,避免大量缓存同时过期。
- 适用场景:适用于所有使用缓存的场景,简单有效,能降低缓存雪崩发生的概率。
- 多级缓存架构:
- 原理:构建多级缓存,例如一级缓存使用Redis,二级缓存可以使用本地缓存(如Guava Cache)。当一级缓存失效时,先从二级缓存获取数据,若二级缓存也没有,再查询数据库。这样可以在一定程度上缓解数据库压力。
- 适用场景:适用于对性能要求较高且允许一定数据不一致的场景,通过多级缓存的层次结构来分散请求压力。
- 分散过期时间:
- 代码实现层面:
- 缓存更新策略优化:
- 原理:在缓存数据过期前,提前进行异步更新,确保缓存数据的连续性。例如在缓存过期前10%的时间内,启动一个异步任务去更新缓存数据。
- 适用场景:适用于对数据实时性要求较高的场景,能在不影响业务使用缓存的情况下,保证缓存数据的有效性。
- 缓存更新策略优化:
- 运维层面:
- 缓存高可用:
- 原理:通过搭建Redis集群,采用主从复制、哨兵模式或Cluster模式,保证缓存服务的高可用性。当某个节点故障时,其他节点可以继续提供服务,减少因缓存服务故障导致的缓存雪崩风险。
- 适用场景:所有依赖缓存的应用场景,通过提升缓存服务的可靠性来防止缓存雪崩。
- 缓存高可用:
- 架构设计层面:
缓存击穿
- 产生原因:
- 热点数据过期:某个热点数据在缓存中过期的瞬间,大量并发请求同时查询该数据,由于缓存中没有,这些请求会同时穿透到数据库,给数据库造成巨大压力。
- 优化策略:
- 架构设计层面:
- 互斥锁:
- 原理:在查询缓存未命中时,先获取一个分布式锁(例如使用Redis的SETNX命令实现),只有获取到锁的请求才能查询数据库并更新缓存,其他请求等待。获取锁的请求更新完缓存后释放锁,其他等待的请求再次查询缓存即可命中。
- 适用场景:适用于对一致性要求较高的热点数据场景,通过加锁机制保证同一时间只有一个请求查询数据库,避免数据库压力过大。
- 互斥锁:
- 代码实现层面:
- 逻辑过期:
- 原理:在缓存数据中设置一个逻辑过期时间,实际缓存数据不过期。当查询缓存数据时,发现逻辑过期,使用一个后台线程去更新缓存数据,前台请求直接返回旧数据。这样可以保证请求不会直接穿透到数据库,同时在一定程度上保证数据的实时性。
- 适用场景:适用于对数据一致性要求不是特别高,但对性能要求较高的热点数据场景,通过逻辑过期和后台更新机制减少对数据库的查询。
- 逻辑过期:
- 运维层面:
- 热点数据持久化:
- 原理:对于热点数据,设置其不过期,或者采用定期更新的方式保证其有效性,避免因过期导致的缓存击穿。
- 适用场景:适用于热点数据明确且数量有限的场景,通过对热点数据特殊处理,确保其始终在缓存中,减少对数据库的冲击。
- 热点数据持久化:
- 架构设计层面: