Redis内存淘汰策略

内存淘汰策略(Eviction Policies),这是 Redis 作为缓存或内存数据库的核心机制,用于在内存不足时,决定如何删除一些数据以腾出空间存储新数据。

一、核心概念:为什么需要内存淘汰?

Redis 是一个基于内存的数据库,所有数据都存放在内存中。而内存是有限且昂贵的资源。当 Redis 使用的内存达到其最大限制时(由配置文件中的 maxmemory 参数指定),继续写入新数据就会触发 Redis 的内存淘汰机制

如果没有这个机制,Redis 会返回错误 (error) OOM command not allowed when used memory > 'maxmemory'

二、如何配置内存淘汰?

redis.conf 配置文件中,有两个关键参数:

  1. 设置内存上限

    # 指定 Redis 最大内存限制,0 表示不限制(64位系统默认),32位系统默认3GB。
    # 强烈建议生产环境必须设置。
    maxmemory 4gb
    
  2. 设置淘汰策略

    # 指定达到内存上限时采用的淘汰策略。
    maxmemory-policy volatile-lru
    

三、八大内存淘汰策略详解

Redis 提供了 8 种策略,可分为三类:不淘汰仅淘汰设置了过期时间的键淘汰所有键


第一类:不淘汰(容易引发错误)

  1. noeviction (默认策略)
    • 行为:当内存不足时,所有会引起内存增加的写命令(如 SET, LPUSH 等)都会返回错误。读命令(如 GET)可以正常执行。
    • 适用场景:如果你把 Redis 当作一个真正的数据库,而不仅仅是缓存,数据绝对不能丢失,那么可以使用此策略。你需要通过其他方式(如扩容)来解决内存问题。

第二类:从设置了过期时间的键中淘汰 (volatile-*)

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

  1. volatile-lru (Least Recently Used - 最近最少使用)

    • 行为:淘汰最近最久未使用并且设置了过期时间的键。
    • 原理:基于“如果数据最近被访问过,那么将来被访问的概率也更高”的思想。它优先淘汰最“冷”的数据。
    • 适用场景最常用的策略。如果你的应用中有明显的热点数据和非热点数据之分,希望保留热点数据,此策略效果很好。
  2. volatile-lfu (Least Frequently Used - 最不经常使用) (Redis 4.0+)

    • 行为:淘汰访问频率最低并且设置了过期时间的键。
    • 原理:LFU 会统计每个键的访问频率(不仅仅是最近访问时间),并淘汰访问次数最少的数据。它比 LRU 能更好地区分“冷热”数据。
    • 适用场景:当某些数据在短时间内被频繁访问,但之后再也不用了,使用 volatile-lru 可能无法及时淘汰它(因为它的最近访问时间很新),而 volatile-lfu 能根据频率更好地识别并淘汰它。
  3. volatile-ttl (Time To Live)

    • 行为:淘汰剩余过期时间最短的键。
    • 原理:优先淘汰即将过期的数据,为即将要过期的数据做“缓刑”。
    • 适用场景:如果你希望尽可能快地清理掉过期数据,让 Redis 中保留的数据都是离过期还有一段时间的数据,可以使用此策略。
  4. volatile-random

    • 行为:从设置了过期时间的键中,随机选择一个进行淘汰。
    • 适用场景:如果你不确定哪种策略好,并且数据的访问模式是均匀的(没有明显的冷热区分),可以用这个简单的策略。

第三类:从所有键中淘汰 (allkeys-*)

这类策略会在所有键(无论是否设置了过期时间)中进行淘汰。这意味着即使没有设置过期时间的“永久”数据也可能被删除。

  1. allkeys-lru

    • 行为:从所有键中淘汰最近最久未使用的键。
    • 适用场景:如果你把 Redis 既当作缓存,又当作持久存储,但其中一些数据的重要性明显低于另一些(即有冷热区分),可以使用此策略。它会保证最热的数据常驻内存。
  2. allkeys-lfu (Redis 4.0+)

    • 行为:从所有键中淘汰访问频率最低的键。
    • 适用场景:同样是混合使用场景,但希望根据访问频率而非最近访问时间来淘汰最“冷”的数据。
  3. allkeys-random

    • 行为:从所有键随机选择一个进行淘汰。
    • 适用场景:如果你的数据访问模式是完全随机的,所有数据被访问的概率都差不多,可以使用此策略。

四、策略选择决策图与最佳实践

如何选择最适合的策略?可以参考以下决策流程:

flowchart TD A[开始选择淘汰策略] --> B{数据能否丢失?}; B -- 绝对不能<br/>(Redis是主要数据库) --> C[选择 noeviction<br/>并确保内存充足]; B -- 可以丢失<br/>(Redis是缓存) --> D{是否所有数据都设置了过期时间?}; D -- 是 --> E{是否有明显的热点数据?}; E -- 是 --> F[选择 volatile-lru<br/>(最常用、最通用)]; E -- 否,访问均匀 --> G[选择 volatile-random]; E -- 否,需按频率淘汰 --> H[选择 volatile-lfu]; D -- 否<br/>(混合使用:缓存+持久存储) --> I{是否有明显的热点数据?}; I -- 是 --> J[选择 allkeys-lru]; I -- 否,访问均匀 --> K[选择 allkeys-random]; I -- 否,需按频率淘汰 --> L[选择 allkeys-lfu];

最佳实践与建议

  1. 一定要设置 maxmemory:这是触发淘汰策略的前提,防止 Redis 耗尽服务器内存导致系统崩溃。
  2. 理解你的数据访问模式
    • 如果你的数据访问有热点,优先选择 volatile-lruallkeys-lru。这是最通用、效果最好的策略。
    • 如果你的数据在短时间内爆发访问后又长期沉寂(例如热点新闻),volatile-lfuallkeys-lfu 可能是更好的选择。
    • 如果你的数据访问模式是完全随机的,可以使用 ...-random 策略。
  3. 缓存 vs 数据库
    • 如果 Redis 只用作纯缓存,所有数据在数据库都有副本,那么优先使用 volatile-* 策略,并为所有缓存键设置合理的过期时间(TTL)。
    • 如果 Redis 是混合使用(部分数据是唯一的),建议使用 allkeys-lru 并合理设置 maxmemory,让 Redis 自己决定淘汰哪些数据。
  4. 监控与调整
    • 使用 INFO 命令或监控工具查看 evicted_keys 指标。如果这个数值持续增长,说明淘汰很频繁,可能需要扩容或优化策略。
    • LRU/LFU 算法在 Redis 中是一种近似算法(为了节省内存),并非绝对精确。你可以通过 maxmemory-samples 配置来调整算法的精确度(默认是5,越大越精确但CPU消耗越多)。
  5. 版本选择:如果可能,尽量使用 Redis 4.0+ 版本,它提供了更优秀的 LFU 策略。

总结:对于大多数将 Redis 作为缓存的场景,volatile-lru 是一个安全且高效的选择。

posted @ 2025-09-05 18:07  xclic  阅读(36)  评论(0)    收藏  举报