当 Redis 使用的内存达到其配置的最大值(maxmemory
)时,它必须决定如何响应后续的写入请求和哪些键应该被移除以释放空间。这个过程就叫做"内存淘汰"。Redis 提供了多种策略供用户选择。
核心策略分类
Redis 的内存淘汰策略主要可以分为两大类:
- 不淘汰数据:在内存不足时,拒绝所有会增加内存使用的写入请求。
- 淘汰数据:根据特定算法移除一些键,以腾出空间容纳新数据。
具体策略详解
以下是 maxmemory-policy
配置项可以设置的所有策略:
第一类:不淘汰策略
noeviction
(默认策略 )- 行为 :当内存达到限制时,所有会引起内存增加的写入命令(如
SET
,LPUSH
,HSet
等)都会返回错误。读请求(如GET
)可以正常执行。 - 适用场景:如果你希望把 Redis 既当缓存又当持久化数据库使用,并且确保数据绝不会被丢失,那么可以使用这个策略。你需要通过其他方式(如升级硬件、优化数据)来处理内存不足的问题。
- 行为 :当内存达到限制时,所有会引起内存增加的写入命令(如
第二类:淘汰策略(在设置了过期时间的键中筛选)
这类策略只会在 设置了过期时间(TTL) 的键中筛选淘汰对象。
-
volatile-lru
(Least Recently Used)- 行为 :从已设置过期时间 的键中,淘汰最近最少使用的键。
- 适用场景:如果你能明确区分热数据和冷数据,并且大部分键都设置了过期时间,这是一个非常通用的缓存策略。
-
volatile-lfu
(Least Frequently Used)- 行为 :从已设置过期时间 的键中,淘汰最不经常使用的键(即访问频率最低的键)。
- 适用场景:相比 LRU,LFU 更关注访问频率。例如,一个键虽然最近刚被访问过,但整个生命周期只被访问了1-2次,而另一个键可能很久没被访问,但之前被访问过成千上万次,LFU 会倾向于保留后者。适合那些访问频率差异很大的业务。
-
volatile-random
- 行为 :从已设置过期时间 的键中,随机选择一个键进行淘汰。
- 适用场景:如果你认为所有键的"重要程度"都差不多,随机淘汰可以提供一个均匀的淘汰分布,实现起来开销也很小。
-
volatile-ttl
(Time To Live)- 行为 :从已设置过期时间 的键中,淘汰剩余存活时间最短的键。
- 适用场景:优先淘汰即将过期的数据,非常适合希望数据能按预期时间自动失效的场景,可以节省内存用于存储更持久的数据。
第三类:淘汰策略(在所有键中筛选)
这类策略会从 所有键 (无论是否设置过期时间)中筛选淘汰对象。使用这类策略会淘汰没有设置过期时间的键,请谨慎使用!
-
allkeys-lru
- 行为 :从所有键 中,淘汰最近最少使用的键。
- 适用场景:如果你的数据访问模式符合幂律分布(即存在明显的热点数据),或者你不确定该用什么策略,这通常是一个很好的选择。它会把内存留给最常用的键。
-
allkeys-lfu
- 行为 :从所有键 中,淘汰最不经常使用的键。
- 适用场景 :与
volatile-lfu
类似,但作用范围是所有键。适用于需要根据访问频率淘汰所有类型数据的场景。
-
allkeys-random
- 行为 :从所有键 中,随机选择一个键进行淘汰。
- 适用场景:如果你希望所有键被淘汰的概率都均等,可以使用这个策略。适用于所有数据重要性都类似的场景。
如何选择策略?
选择策略的核心在于明确你的数据特性和 Redis 的角色(是纯缓存还是持久化存储)。
你的需求 | 推荐策略 |
---|---|
数据不能丢,内存不足时应由应用层处理 | noeviction |
Redis 仅作为缓存,所有数据在磁盘数据库中有备份 | allkeys-lru 或 allkeys-lfu (最常用) |
希望长时间保留某些特定键(如用户配置),其他键作为缓存 | 对特定键不设置 TTL ,然后使用 volatile-lru 或 volatile-lfu |
单个缓存实例为多个不确定性应用服务,访问模式难以预测 | allkeys-random |
希望数据尽可能按设定的时间过期,以节省内存 | volatile-ttl |
配置方法
在 redis.conf
配置文件中设置:
bash
# 设置最大内存,例如 100MB
maxmemory 100mb
# 设置淘汰策略,例如 allkeys-lru
maxmemory-policy allkeys-lru
也可以在运行时使用 CONFIG SET
命令动态修改:
bash
127.0.0.1:6379> CONFIG SET maxmemory 100mb
127.0.0.1:6379> CONFIG SET maxmemory-policy allkeys-lru
补充说明:近似算法
出于对性能和内存的考虑,Redis 使用的 LRU 和 LFU 并非是完全精确的实现,而是近似算法。
- LRU :Redis 会随机采样一小部分键(数量由
maxmemory-samples
配置,默认是5),然后从这批样本中淘汰最久未使用的那个。采样数量越大,结果越精确,但CPU消耗也越大。 - LFU:Redis 会为每个键维护一个访问计数器。计数器会随着时间衰减。新的访问会使计数器增加,但增加的概率和速率会受到控制。
这种设计在保证了高性能的同时,也能达到非常好的淘汰效果。
总结
策略名称 | 筛选范围 | 淘汰规则 | 说明 |
---|---|---|---|
noeviction |
- | 不淘汰,返回错误 | 默认策略,保证数据不丢失 |
volatile-lru |
设定了过期时间的键 | 最近最少使用 | 常用缓存策略 |
volatile-lfu |
设定了过期时间的键 | 最不经常使用 | 按访问频率淘汰 |
volatile-random |
设定了过期时间的键 | 随机 | 简单高效 |
volatile-ttl |
设定了过期时间的键 | 剩余时间最短 | 优先淘汰快过期的数据 |
allkeys-lru |
所有键 | 最近最少使用 | 最常用的全能型缓存策略 |
allkeys-lfu |
所有键 | 最不经常使用 | 按访问频率淘汰所有数据 |
allkeys-random |
所有键 | 随机 | 所有键平等淘汰 |
希望这个详细的解释能帮助你更好地理解和选择 Redis 的内存淘汰策略!