Redis内存淘汰策略介绍
当 Redis 的内存使用达到设定的上限 (maxmemory) 时,会触发内存淘汰策略,以确保有足够的空间来处理新的写入请求。这些策略决定了在内存不足时哪些键应该被删除。以下是 Redis 内存淘汰策略的详细介绍。
如何配置内存淘汰策略
在 Redis 中,通过以下两个配置指令来控制内存淘汰:
maxmemory <bytes>: 设置 Redis 可以使用的最大内存。当内存使用达到这个阈值时,就会触发淘汰策略。可以在redis.conf文件中设置,或者通过CONFIG SET命令在运行时动态修改。maxmemory-policy <policy>: 设置具体的内存淘汰策略。
八种内存淘汰策略
Redis 提供了八种不同的内存淘汰策略,可以分为两大类:针对所有键和仅针对设置了过期时间的键。
不淘汰策略
- noeviction:
- 描述: 这是 Redis 的默认策略。当内存使用达到
maxmemory上限时,不会删除任何数据。相反,对于会导致内存增加的写入命令(如SET,LPUSH等),Redis 会返回错误。但读命令仍然可以正常执行。 - 适用场景: 当每个键都非常重要,不允许因为内存不足而被删除时。适用于将 Redis 作为持久化存储而非缓存的场景。
- 描述: 这是 Redis 的默认策略。当内存使用达到
针对所有键 (allkeys) 的淘汰策略
这些策略会从所有的键中(无论是否设置了过期时间)选取要淘汰的数据。
-
allkeys-lru:
- 描述: 采用近似 LRU (Least Recently Used) 算法,从所有键中淘汰最近最少使用的数据。 Redis 并非实现了一个完美的 LRU,而是通过对少量键进行采样,并从中选择最久未被访问的键进行淘汰。
- 适用场景: 当你预期数据集中有一部分数据会被频繁访问,而其他数据则很少被访问时,这是一个很好的选择(符合帕累托法则)。这是最常用的策略之一。
-
allkeys-lfu:
- 描述: 从 Redis 4.0 开始引入,采用近似 LFU (Least Frequently Used) 算法,从所有键中淘汰访问频率最低的数据。 LFU 会跟踪每个键的访问频率,优先淘汰那些很少被访问的键。 如果访问频率相同,则会比较访问时间的远近。
- 适用场景: 如果你的应用场景中,某些数据在一段时间内会被持续高频访问,而 LRU 策略可能会因为一些偶然的近期访问而保留不重要的数据,此时 LFU 是更好的选择。
-
allkeys-random:
- 描述: 从所有键中随机选择一个键进行淘汰。
- 适用场景: 当所有键的访问模式没有明显的热点区分,访问概率大致相同时,可以使用此策略。
仅针对设置了过期时间的键 (volatile) 的淘汰策略
这些策略只会从设置了过期时间(TTL)的键中进行淘汰。
-
volatile-lru:
- 描述: 采用近似 LRU 算法,从设置了过期时间的键中淘汰最近最少使用的数据。
- 适用场景: 当你希望保留那些没有设置过期时间的持久化数据,而只在需要时淘汰那些作为缓存且设置了过期时间的数据时使用。
-
volatile-lfu:
- 描述: 从 Redis 4.0 开始引入,采用近似 LFU 算法,从设置了过期时间的键中淘汰访问频率最低的数据。
- 适用场景: 与
allkeys-lfu类似,但淘汰范围仅限于设置了过期时间的键。
-
volatile-random:
- 描述: 从设置了过期时间的键中随机选择一个进行淘汰。
- 适用场景: 当设置了过期时间的键没有明显的访问优先级时使用。
-
volatile-ttl:
- 描述: 从设置了过期时间的键中,选择剩余生存时间(TTL)最短的键进行淘汰。
- 适用场景: 当你可以通过为键设置不同的过期时间来预估其重要性时,这个策略非常有用。 它可以帮助优化性能,优先淘汰即将过期的数据,从而保留更多有效数据。
重要提示:如果使用 volatile-* 策略,但当前内存中没有设置过期时间的键,那么在内存满时,其行为将和 noeviction 策略一样,不会淘汰任何数据,并对写操作返回错误。
如何选择合适的淘汰策略
选择哪种淘汰策略取决于你的应用场景和数据访问模式:
- 通用缓存场景: 如果不确定使用哪种策略,
allkeys-lru是一个很好的起点,因为它在很多场景下都表现良好。 - 热点数据明显: 如果你的应用有明显的热点数据,
allkeys-lru或allkeys-lfu通常是最佳选择。LFU 能更好地处理那些在一段时间内被集中访问的数据。 - 访问模式平均: 如果所有数据的访问频率和概率都差不多,
allkeys-random是一个不错的选择。 - 临时缓存与持久数据共存: 如果你的 Redis 中同时存储了需要持久化的数据和临时缓存数据,应该使用
volatile-*策略,并为缓存数据设置过期时间。这样可以确保持久化的数据不会被淘汰。 - 基于过期时间的优先级: 如果你可以通过过期时间的设置来控制数据的优先级,
volatile-ttl是一个非常有效的策略。
| 策略 | 描述 |
|---|---|
| noeviction | 默认策略,内存满时写入报错,不删除任何数据。 |
| allkeys-lru | 从所有键中淘汰最久未使用的键。 |
| allkeys-lfu | 从所有键中淘汰使用频率最低的键。 |
| allkeys-random | 从所有键中随机淘汰一个键。 |
| volatile-lru | 从设置了过期时间的键中淘汰最久未使用的键。 |
| volatile-lfu | 从设置了过期时间的键中淘汰使用频率最低的键。 |
| volatile-random | 从设置了过期时间的键中随机淘汰一个键。 |
| volatile-ttl | 从设置了过期时间的键中淘汰剩余生存时间最短的键。 |