Redis 为什么需要淘汰策略?

Redis 是一个基于内存的数据库/缓存,当实际使用的内存量超过 maxmemory 参数设置的最大限制时,Redis 会根据配置的淘汰策略(Eviction Policy) 来移除一些键,以便为新数据腾出空间。


Redis 的淘汰策略有哪些?

Redis 提供了 8 种淘汰策略,可以分为两大类:

第一类:处理过期键的策略(只针对设置了 TTL 过期的键)

这组策略只在有过期时间的键中进行淘汰。

  1. volatile-lru (Least Recently Used)

    • 机制:从设置了过期时间的键中,淘汰最近最少使用的键。
    • 理解:基于时间戳,认为最近没被访问的键以后也不太可能被访问。
  2. volatile-lfu (Least Frequently Used)

    • 机制:从设置了过期时间的键中,淘汰最不经常使用的键。
    • 理解:基于访问频率计数器,认为访问次数最少的键是最不重要的。这是 Redis 4.0 及以上版本新增的策略。
  3. volatile-random

    • 机制:从设置了过期时间的键中,随机淘汰某个键。
    • 理解:简单粗暴,没有开销,但效果不确定。
  4. volatile-ttl

    • 机制:从设置了过期时间的键中,淘汰存活时间最短(TTL 最小)的键,即即将过期的键。
    • 理解:优先清理马上要过期的数据,尽量保留还有很久才过期的数据。

第二类:在所有键中进行的策略(包括无过期时间的键)

这组策略会在所有键中进行淘汰,无论是否设置了 TTL。这是最常用的策略类型,因为它能防止没有设置 TTL 的键导致内存爆满。

  1. allkeys-lru

    • 机制:从所有键中,淘汰最近最少使用的键。
    • 理解:这是最常用的策略之一,非常适合作为缓存系统使用。
  2. allkeys-lfu

    • 机制:从所有键中,淘汰最不经常使用的键。
    • 理解:同样是 Redis 4.0+ 新增的策略,适用于非常关注访问频率的场景。
  3. allkeys-random

    • 机制:从所有键中,随机淘汰某个键。
    • 理解:如果你认为所有键被访问的概率都差不多,可以用这个。
  4. no-eviction

    • 机制禁止淘汰数据。当内存不足时,所有会引起内存增加的写入命令(如 SET, LPUSH 等)都会报错,读命令(GET 等)可以正常执行。
    • 理解:这保证了数据不会丢失,但需要上层应用处理好写入异常。适用于你把 Redis 既当缓存又当持久存储,且数据绝对不能丢失的场景。

如何选择比较好的淘汰策略?

选择策略的核心原则是:根据你的数据特征和访问模式来决定。以下是一些通用的建议:

1. 首先,问自己一个问题:Redis 在你的系统中扮演什么角色?

  • 纯缓存(Cache):数据可以从后端数据库恢复,丢失没关系。目标是提供高速访问。

    • 推荐allkeys-lruallkeys-lfu
    • 原因:它们能有效地根据访问模式保留热点数据,淘汰冷数据,最大化缓存命中率。
  • 持久化存储(Persistent Store):数据必须保留,不能丢失。

    • 推荐no-eviction
    • 原因:宁可拒绝写入也要保证已有数据完整。你需要确保你的 maxmemory 设置得足够大,并且有监控报警,在内存快满时及时处理(如扩容或清理数据)。

2. 其次,分析你的数据访问模式

  • 存在热点数据,访问遵循二八定律(20% 的键承担了 80% 的访问):

    • 推荐allkeys-lru。它能非常高效地识别并保留热点数据。
  • 访问频率分布相对平均,但某些键在一段时间内被频繁访问(扫描式访问)

    • 推荐allkeys-lfu。LFU 算法比 LRU 更能应对短期的爆发性访问,因为它关注的是频率而非最近一次访问时间。例如,一个键在短时间内被大量访问,LFU 会认为它很重要并保留,而 LRU 可能会因为它之后没被访问而将其淘汰。
  • 所有键被访问的概率几乎完全相同,毫无规律

    • 可以考虑allkeys-random。这是一种简单且开销低的公平策略。
  • 你希望通过 TTL 来精准控制数据淘汰的优先级

    • 推荐volatile-ttl。你希望那些即将过期的数据被优先清理掉。注意:如果你有键没设置 TTL,它们就永远不会被此策略淘汰,可能导致内存溢出。

3. 考虑你的 Redis 版本

  • 如果你的 Redis 是 4.0 以下的旧版本,你没有 volatile-lfuallkeys-lfu 这两个选项。
  • 建议优先使用 allkeys-lru

总结与决策流程图

你可以遵循以下流程来做出选择:

graph TD
    A[开始选择] --> B{Redis的主要角色是?};
    B -->|纯缓存| C{数据访问模式?};
    B -->|持久化存储,数据不能丢| D[选择 no-eviction];

    C -->|存在热点数据| E[选择 allkeys-lru
最通用推荐]; C -->|访问频率变化大,有爆发访问| F[选择 allkeys-lfu
(Redis 4.0+)]; C -->|所有键访问概率均等| G[选择 allkeys-random]; E --> H[完成]; F --> H; G --> H; D --> H;

最终建议:

对于绝大多数将 Redis 作为缓存的场景,allkeys-lru 是一个安全、高效且通用的选择,可以作为你的默认选项。如果你的访问模式更复杂且版本在 4.0 以上,可以尝试使用 allkeys-lfu 以获得更好的命中率。