Redis 缓存击穿(失效)、缓存穿透、缓存雪崩怎么解决?

Redis 缓存击穿(失效)、缓存穿透、缓存雪崩怎么解决?
最新回答
下次请我

2021-09-08 06:52:11

Redis 缓存击穿(失效)、缓存穿透、缓存雪崩是缓存使用中常见的三个问题,以下是具体分析和解决方案:

缓存击穿(失效)

定义:高并发流量访问热点数据,该数据在数据库中存在,但 Redis 中的缓存已过期,导致大量请求直接访问数据库,可能压垮数据库。关键字:单一热点数据、高并发、数据失效。

解决方案

  • 过期时间 + 随机值

    为热点数据设置过期时间时,采用公式:过期时间 = 基础时间 + 随机时间(如 1~5 分钟)。

    避免大量热点数据同时过期,减少对数据库的瞬时压力。

  • 预热

    提前将热门数据存入 Redis,并设置超长过期时间(如 24 小时),确保缓存始终有效。

  • 使用锁

    当缓存失效时,先获取分布式锁,成功后再执行数据库查询和缓存更新操作。

    伪代码如下:

public Object getData(String id) { String desc = redis.get(id); if (desc == null) { if (redis(lockName)) { try { desc = getFromDB(id); redis.set(id, desc, 60 * 60 * 24); } catch (Exception ex) { LogHelper.error(ex); } finally { redis.del(lockName); return desc; } } else { Thread.sleep(200); return getData(id); } } return desc;}缓存穿透

定义:请求查询的数据在 Redis 和数据库中均不存在,导致每次请求都穿透到数据库,增加数据库压力。

解决方案

  • 缓存空值

    当数据不存在时,在 Redis 中缓存一个空值(如 None),后续查询直接返回空值,避免重复访问数据库。

  • 布隆过滤器

    将数据库中的所有 key 存入布隆过滤器,查询时先检查过滤器。若 key 不存在,则直接返回,避免访问数据库。

    原理

    使用 bit 数组和多个哈希函数,将 key 映射到数组的多个位置并设置为 1。

    查询时,若所有映射位置均为 1,则可能存在;否则一定不存在。

    存在误判率(可能误判存在,但实际不存在),但不会漏判。

    适用场景:全量 key 数量不大(如 10 亿条以内),占用内存约 1.2GB。

缓存雪崩

定义:大量请求无法在 Redis 中处理,直接访问数据库,导致数据库压力激增甚至宕机。原因

  • 大量热点数据同时过期。
  • Redis 故障宕机。

解决方案

针对大量数据同时过期:
  • 过期时间添加随机值

    为缓存设置过期时间时,增加随机值(如 1~5 分钟),避免大量数据同时失效。

  • 接口限流

    对非核心数据接口设置限流(如 10000 req/s),减少数据库访问压力。

    核心数据接口允许从数据库查询并更新缓存。

针对 Redis 故障宕机:
  • 服务熔断和限流

    当缓存异常时,直接返回错误数据或默认值,避免流量涌入数据库。

    熔断机制可防止系统崩溃,限流控制请求量。

  • 构建高可用缓存集群

    使用 Redis 哨兵集群或 Redis Cluster,实现主从切换和故障自动恢复。

    确保缓存服务的高可用性,避免单点故障导致雪崩。

总结
  • 缓存穿透:数据库无数据,请求直达数据库。解决方案包括缓存空值和使用布隆过滤器。
  • 缓存击穿(失效):热点数据缓存过期,请求直达数据库。解决方案包括过期时间加随机值、预热和使用锁。
  • 缓存雪崩:大量热点数据失效或 Redis 故障,请求直达数据库。解决方案包括过期时间加随机值、接口限流、服务熔断和构建高可用集群。

通过合理设计缓存策略和应对措施,可有效避免上述问题,提升系统性能和稳定性。