Redis内存淘汰策略LRU和LFU的区别与配置
当 Redis 使用的内存大小达到配置的上限(maxmemory)时,为了继续提供服务,它必须执行内存淘汰策略,即删除部分已有的键值对以释放内存空间。LRU(Least Recently Used)和 LFU(Least Frequently Used)是其中最核心的两种算法。理解它们的区别并正确配置,是保证 Redis 高性能运行的关键。
LRU 与 LFU 的核心区别
LRU 和 LFU 的根本区别在于判断“谁该被删除”的维度不同:一个是基于“时间”,一个是基于“频率”。
1. LRU (Least Recently Used) 算法
LRU 算法的核心思想是:如果一个数据最近没有被访问过,那么将来被访问的概率也很低。
- 淘汰依据:最后一次访问的时间。
- 操作逻辑:当内存不足时,优先淘汰最久没有被访问过的键。
- 适用场景:适合“热点数据”随时间变化比较明显的业务。例如,新闻资讯网站,大家都在看突发新闻(此时它是热点),过几个小时没人看了(变冷),就应该被淘汰。
2. LFU (Least Frequently Used) 算法
LFU 算法的核心思想是:如果一个数据在过去的访问频率很低,那么将来被访问的概率也很低。
- 淘汰依据:历史访问的频率(次数)。
- 操作逻辑:当内存不足时,优先淘汰访问频率最低的键。
- 适用场景:适合“高频数据”长期稳定的业务。例如,某些基础配置数据或字典类接口,这些数据一旦被加载,会被反复调用,且短时间内不会变冷。
Redis 中的实现细节(近似算法)
为了保证高性能,Redis 并没有使用完美的 LRU 或 LFU 算法,因为完美的算法需要消耗大量的内存来维护复杂的结构。Redis 使用的是近似算法。
1. Redis 的 LRU 实现机制
Redis 并不会为所有键维护一个全局的精确链表。它采用了一种随机采样的策略:
- 配置采样参数:Redis 配置文件中有一个参数
maxmemory-samples,默认值通常是 5。 - 随机选取:当需要淘汰数据时,Redis 会从所有键中随机选取 N 个(即
maxmemory-samples的值)键。 - 比较淘汰:在这 N 个键中,淘汰掉最久没有被访问的那个键。
2. Redis 的 LFU 实现机制
Redis 4.0 之后引入了 LFU 策略。为了更智能地反映访问热度,Redis 使用了一个名为 Morris Counter 的概率计数器,并且引入了“衰减”机制:
- 计数器:每个键维护一个计数器,每次访问计数器增加,但增加的幅度是随机的(访问次数越多,增加的概率越大)。
- 衰减因子:如果这个键很久没被访问,Redis 会通过一个公式降低它的计数值(类似“冷却”),防止很久以前的冷数据因为积累了历史点击量而一直占用内存。
LRU 与 LFU 对比总结
下表总结了两种策略在不同维度下的特性:
| 特性 | LRU (Least Recently Used) | LFU (Least Frequently Used) |
|---|---|---|
| 判断标准 | 距离上一次访问的时间长短 | 历史访问的总次数 |
| 核心逻辑 | 淘汰“最久”没用的 | 淘汰“最少”被用的 |
| 对突发流量的处理 | 敏感:突发的读取会让该键变为热点,不被淘汰 | 不敏感:突发读取不会立即让计数值超过老的热点数据 |
| 适用场景 | 周期性访问、时间相关性强的数据 | 高频稳定访问、需要过滤偶发性访问的数据 |
| 计算开销 | 极低 | 较低(略高于 LRU,需维护计数器) |
内存淘汰策略配置步骤
Redis 提供了多种具体的策略配置,它们通常分为针对所有键(allkeys)和仅针对设置了过期时间的键(volatile)两类。以下是配置和修改的详细步骤。
第一步:修改配置文件(永久生效)
这是最稳妥的配置方式,修改后重启 Redis 依然有效。
-
打开 Redis 的配置文件
redis.conf。 -
搜索 并找到
maxmemory配置项。 -
取消注释 并设置最大内存限制(例如设置为 1GB)。
maxmemory 1gb -
搜索 并找到
maxmemory-policy配置项。 -
取消注释 并将其设置为你需要的策略值。
常用的策略值包括:
noeviction:默认策略,内存满时不删除,直接报错。allkeys-lru:对所有键使用 LRU 淘汰。volatile-lru:仅在设置了过期时间的键中使用 LRU 淘汰。allkeys-lfu:对所有键使用 LFU 淘汰(Redis 4.0+)。volatile-lfu:仅在设置了过期时间的键中使用 LFU 淘汰(Redis 4.0+)。allkeys-random:对所有键随机淘汰。volatile-random:在设置了过期时间的键中随机淘汰。volatile-ttl:淘汰剩余生存时间(TTL)最短的键。
例如,配置为对所有键使用 LRU:
maxmemory-policy allkeys-lru -
保存 配置文件。
-
重启 Redis 服务使配置生效。
第二步:使用命令行动态配置(无需重启)
如果你不想重启服务,或者想临时测试策略,可以使用 redis-cli 连接到服务器进行动态修改。
- 连接 到 Redis 服务。
redis-cli - 设置 最大内存(如果尚未设置)。
CONFIG SET maxmemory 1gb - 设置 淘汰策略。
例如,切换到 LFU 模式:CONFIG SET maxmemory-policy allkeys-lfu - 验证 配置是否成功。
CONFIG GET maxmemory-policy输出结果应包含
allkeys-lfu。
如何调整 LRU/LFU 的精度
如果你发现 Redis 的淘汰效果不够理想(例如该保留的热点数据被误删了),可以通过调整采样数量来提高算法的精确度,但会增加少许 CPU 消耗。
-
编辑
redis.conf文件。 -
找到
maxmemory-samples配置项。 -
修改 数值。默认值为 5,建议范围是 5 到 10。值越大,结果越接近完美的 LRU/LFU,但 CPU 消耗也越高。
例如,设置为 10:
maxmemory-samples 10 -
保存 并重启 Redis,或者使用命令:
CONFIG SET maxmemory-samples 10
实战中的策略选择建议
在实际生产环境中,选择哪种策略取决于你的数据访问模式:
-
如果你的数据主要是缓存数据,且没有设置过期时间:
建议使用allkeys-lru。这是最通用的策略,能有效保留最近被访问的数据。 -
如果你的数据主要是缓存数据,但存在某些极其频繁访问的“钉子户”数据:
建议使用allkeys-lfu。它能有效过滤掉偶尔被访问一次的“噪音”数据,保留真正的高频核心数据。 -
如果你主要希望缓存某些带过期时间的会话或临时数据:
建议使用volatile-lru或volatile-lfu。这可以确保未设置过期时间的永久数据不会被意外删除,仅利用空闲内存来缓存临时数据。 -
如果是做简单的缓存,不希望复杂的逻辑:
使用默认的noeviction配合合理的过期时间策略,或者直接使用allkeys-random(在数据集较小且访问均匀时效果尚可)。

暂无评论,快来抢沙发吧!