Skip to content

Redis内存淘汰策略介绍

当 Redis 的内存使用达到设定的上限 (maxmemory) 时,会触发内存淘汰策略,以确保有足够的空间来处理新的写入请求。这些策略决定了在内存不足时哪些键应该被删除。以下是 Redis 内存淘汰策略的详细介绍。

如何配置内存淘汰策略

在 Redis 中,通过以下两个配置指令来控制内存淘汰:

  • maxmemory <bytes>: 设置 Redis 可以使用的最大内存。当内存使用达到这个阈值时,就会触发淘汰策略。可以在 redis.conf 文件中设置,或者通过 CONFIG SET 命令在运行时动态修改。
  • maxmemory-policy <policy>: 设置具体的内存淘汰策略。

八种内存淘汰策略

Redis 提供了八种不同的内存淘汰策略,可以分为两大类:针对所有键和仅针对设置了过期时间的键。

不淘汰策略

  1. noeviction:
    • 描述: 这是 Redis 的默认策略。当内存使用达到 maxmemory 上限时,不会删除任何数据。相反,对于会导致内存增加的写入命令(如 SET, LPUSH 等),Redis 会返回错误。但读命令仍然可以正常执行。
    • 适用场景: 当每个键都非常重要,不允许因为内存不足而被删除时。适用于将 Redis 作为持久化存储而非缓存的场景。

针对所有键 (allkeys) 的淘汰策略

这些策略会从所有的键中(无论是否设置了过期时间)选取要淘汰的数据。

  1. allkeys-lru:

    • 描述: 采用近似 LRU (Least Recently Used) 算法,从所有键中淘汰最近最少使用的数据。 Redis 并非实现了一个完美的 LRU,而是通过对少量键进行采样,并从中选择最久未被访问的键进行淘汰。
    • 适用场景: 当你预期数据集中有一部分数据会被频繁访问,而其他数据则很少被访问时,这是一个很好的选择(符合帕累托法则)。这是最常用的策略之一。
  2. allkeys-lfu:

    • 描述: 从 Redis 4.0 开始引入,采用近似 LFU (Least Frequently Used) 算法,从所有键中淘汰访问频率最低的数据。 LFU 会跟踪每个键的访问频率,优先淘汰那些很少被访问的键。 如果访问频率相同,则会比较访问时间的远近。
    • 适用场景: 如果你的应用场景中,某些数据在一段时间内会被持续高频访问,而 LRU 策略可能会因为一些偶然的近期访问而保留不重要的数据,此时 LFU 是更好的选择。
  3. allkeys-random:

    • 描述: 从所有键中随机选择一个键进行淘汰。
    • 适用场景: 当所有键的访问模式没有明显的热点区分,访问概率大致相同时,可以使用此策略。

仅针对设置了过期时间的键 (volatile) 的淘汰策略

这些策略只会从设置了过期时间(TTL)的键中进行淘汰。

  1. volatile-lru:

    • 描述: 采用近似 LRU 算法,从设置了过期时间的键中淘汰最近最少使用的数据。
    • 适用场景: 当你希望保留那些没有设置过期时间的持久化数据,而只在需要时淘汰那些作为缓存且设置了过期时间的数据时使用。
  2. volatile-lfu:

    • 描述: 从 Redis 4.0 开始引入,采用近似 LFU 算法,从设置了过期时间的键中淘汰访问频率最低的数据。
    • 适用场景: 与 allkeys-lfu 类似,但淘汰范围仅限于设置了过期时间的键。
  3. volatile-random:

    • 描述: 从设置了过期时间的键中随机选择一个进行淘汰。
    • 适用场景: 当设置了过期时间的键没有明显的访问优先级时使用。
  4. volatile-ttl:

    • 描述: 从设置了过期时间的键中,选择剩余生存时间(TTL)最短的键进行淘汰。
    • 适用场景: 当你可以通过为键设置不同的过期时间来预估其重要性时,这个策略非常有用。 它可以帮助优化性能,优先淘汰即将过期的数据,从而保留更多有效数据。

重要提示:如果使用 volatile-* 策略,但当前内存中没有设置过期时间的键,那么在内存满时,其行为将和 noeviction 策略一样,不会淘汰任何数据,并对写操作返回错误。

如何选择合适的淘汰策略

选择哪种淘汰策略取决于你的应用场景和数据访问模式:

  • 通用缓存场景: 如果不确定使用哪种策略,allkeys-lru 是一个很好的起点,因为它在很多场景下都表现良好。
  • 热点数据明显: 如果你的应用有明显的热点数据,allkeys-lruallkeys-lfu 通常是最佳选择。LFU 能更好地处理那些在一段时间内被集中访问的数据。
  • 访问模式平均: 如果所有数据的访问频率和概率都差不多,allkeys-random 是一个不错的选择。
  • 临时缓存与持久数据共存: 如果你的 Redis 中同时存储了需要持久化的数据和临时缓存数据,应该使用 volatile-* 策略,并为缓存数据设置过期时间。这样可以确保持久化的数据不会被淘汰。
  • 基于过期时间的优先级: 如果你可以通过过期时间的设置来控制数据的优先级,volatile-ttl 是一个非常有效的策略。
策略 描述
noeviction 默认策略,内存满时写入报错,不删除任何数据。
allkeys-lru 从所有键中淘汰最久未使用的键。
allkeys-lfu 从所有键中淘汰使用频率最低的键。
allkeys-random 从所有键中随机淘汰一个键。
volatile-lru 从设置了过期时间的键中淘汰最久未使用的键。
volatile-lfu 从设置了过期时间的键中淘汰使用频率最低的键。
volatile-random 从设置了过期时间的键中随机淘汰一个键。
volatile-ttl 从设置了过期时间的键中淘汰剩余生存时间最短的键。