Redis面试题:Redis缓存如何回收?击穿、穿透、雪崩、预热解决方案?

高分请问下,Redis面试题:Redis缓存如何回收?击穿、穿透、雪崩、预热解决方案?
最新回答
无心

2026-10-24 16:58:20

Redis缓存回收及常见问题解决方案

Redis缓存回收策略

Redis提供了多种内存回收策略,当内存使用达到maxmemory限制时,会根据配置的策略进行数据回收,主要策略包括:

  • noeviction:当内存限制达到时,客户端尝试执行会让更多内存被使用的命令(大部分写入指令,DEL和几个例外除外)会返回错误。
  • allkeys-lru:回收最少使用的键(LRU算法),适用于所有键,使得新添加的数据有空间存放。
  • volatile-lru:回收最少使用的键(LRU算法),但仅限于在过期集合的键。
  • allkeys-random:随机回收键,适用于所有键,使得新添加的数据有空间存放。
  • volatile-random:随机回收键,但仅限于在过期集合的键。
  • volatile-ttl:回收过期集合中的键,优先回收存活时间(TTL)较短的键。
  • volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键。
  • allkeys-lfu:从所有键中驱逐使用频率最少的键。

策略选择建议:

  • allkeys-lru:适用于请求符合幂定律分布(部分子集元素被访问更多)的场景,若不确定选择何种策略,这是一个不错的选择。
  • allkeys-random:适用于循环访问或请求分布均匀(所有元素被访问概率相近)的场景。
  • volatile-ttl:适用于希望通过设置TTL值来决定哪些对象应被过期的场景。

回收进程工作原理:

  • 客户端执行新命令添加数据。
  • Redis检查内存使用情况,若超过maxmemory限制,则根据设定策略进行回收。
  • 不断重复上述过程,保持内存使用在限制范围内。

缓存穿透、击穿、雪崩及预热解决方案

缓存穿透

定义:查询一个一定不存在的数据,由于缓存不命中且不写入缓存,导致每次请求都需查询存储层,在流量大时可能压垮数据库。

解决方案:

  • 布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmap中,拦截不存在的数据请求。
  • 缓存空结果:将查询返回的空结果(数据不存在或系统故障)进行缓存,设置较短过期时间(最长不超过五分钟)。
缓存击穿

定义:针对设置了过期时间的热点key,在缓存过期时,大量并发请求同时访问该key,导致请求全部转发到数据库,可能压垮数据库。

解决方案:

  • 分散过期时间:在原有失效时间基础上增加一个随机值(如1-5分钟随机),降低缓存过期时间重复率,避免集体失效。
  • 加锁或队列:使用加锁或队列方式保证缓存的单线程(进程)写,避免失效时大量并发请求落到底层存储系统。
缓存雪崩

定义:设置缓存时采用相同过期时间,导致缓存在某一时刻同时失效,请求全部转发到数据库,造成数据库瞬时压力过重。

解决方案:

  • 互斥锁(mutex key):

    在缓存失效时,先使用SETNX等操作设置一个mutex key。

    若操作返回成功,再进行数据库加载数据并回设缓存;否则重试获取缓存。

  • 提前使用互斥锁:

    在value内部设置一个比实际缓存过期时间短的超时值(timeout1)。

    当从缓存读取到timeout1发现过期时,延长timeout1并重新设置到缓存,再从数据库加载数据并设置到缓存。

  • 永远不过期:

    物理不过期:从Redis角度看,不设置过期时间。

    逻辑过期:将过期时间存在key对应的value里,通过后台异步线程进行缓存构建。

缓存预热

定义:系统启动前,提前将相关数据加载到缓存中,避免系统启动后因缓存未命中导致大量请求直接访问数据库。

解决方案:

  • 手动加载:系统启动时,通过脚本或程序手动将热点数据加载到缓存。
  • 定时任务:设置定时任务,在系统低峰期自动将热点数据加载到缓存。

总结

  • 穿透:缓存不存在,数据库不存在,高并发,少量key。可通过布隆过滤器或缓存空结果解决。
  • 击穿:缓存不存在,数据库存在,高并发,少量key。可通过分散过期时间或加锁解决。
  • 雪崩:缓存不存在,数据库存在,高并发,大量key。可通过互斥锁、提前使用互斥锁或永远不过期策略解决。
  • 预热:系统启动前提前加载热点数据到缓存,避免启动后大量请求直接访问数据库。