在高并发场景中,Redis 常被用作缓存以减轻数据库压力。但由于 Redis 的内存是有限的,当数据量超过设定的最大内存(maxmemory
)时,就需要触发 内存淘汰策略 来删除部分数据,从而为新数据腾出空间。
Redis 提供了多种内存淘汰算法,主要可以归纳为以下四类:
1. 随机淘汰(Random)
策略说明:当内存不足时,Redis 会随机选择并移除一个 key。
优点:实现简单,开销极低。
缺点:完全随机,可能会淘汰掉热门数据,对缓存命中率影响较大。
适用场景:数据价值相对均等、无明显热点的数据场景。
2. TTL 淘汰(Expire)
策略说明:只从设置了过期时间的 key 中挑选即将过期的 key 删除,优先清理快要过期的缓存。
优点:能够优先释放掉“寿命快结束”的数据,合理性较强。
缺点:如果大部分 key 没有设置 TTL,则效果有限。
适用场景:业务中大量数据都带有过期时间(如会话、临时 Token)的情况。
3. LRU(Least Recently Used,最近最少使用)
策略说明:淘汰最近最少访问的 key。
实现机制:
Redis 并非严格的 LRU,而是采用 近似 LRU 算法。
内部维护一个候选池(默认大小 16),随机挑选若干 key(默认 5 个)放入池中,再淘汰其中最久未访问的一个。
优点:能较好地保留近期热点数据,提升缓存命中率。
缺点:存在“热点重现”问题。如果一个长期未访问的 key 突然被访问,它会被 Redis 当成热点,从而延迟淘汰。
适用场景:热点数据占比较大,但访问模式不固定的业务。
4. LFU(Least Frequently Used,最近最少使用频率)
策略说明:淘汰访问频率最低的 key。Redis 从 4.0 版本开始支持。
实现机制:
每个 key 都维护一个访问计数器,初始值为 1。
每次访问 key 时,计数器递增。
为避免计数器“无限增大”而导致数据长期无法淘汰,Redis 会对计数器进行 时间衰减:如果一段时间没有被访问,计数会逐渐降低。
优点:比 LRU 更准确地保留真正的热点数据。
缺点:实现复杂度和维护开销比 LRU 高。
适用场景:热点数据稳定存在(如推荐系统、商品缓存),需要尽量提高缓存命中率的业务。
5. 如何选择合适的策略?
Redis 默认配置下不会启用淘汰策略(即 noeviction
,达到内存上限后直接报错),因此在生产环境中通常需要主动设置合适的策略:
随机淘汰:适合无明显热点、数据价值差不多的场景。
TTL 淘汰:适合大量临时数据(如 Session 缓存)。
LRU:适合大多数通用缓存场景,性能与命中率兼顾。
LFU:适合数据访问频率差异显著,且对命中率要求极高的场景。
可以通过 redis.conf
或命令行配置内存淘汰策略:
# 查看当前内存淘汰策略
CONFIG GET maxmemory-policy
# 设置为 LRU 策略
CONFIG SET maxmemory-policy allkeys-lru
总结
Redis 提供了多种内存淘汰策略,分别适应不同的业务场景:
Random:效率高但命中率低;
Expire:依赖过期时间;
LRU:通用、性能好,但可能误判热点;
LFU:最智能,但开销最大。
在实际应用中,最常见的选择是 allkeys-lru 或 allkeys-lfu,具体取决于业务的访问模式和命中率要求。