Redis 是一个高性能的键值存储数据库,广泛用于缓存、会话存储、消息队列、消息中间件和数据库等场景。Redis 的内存是有限的,当内存使用达到上限时,Redis 需要通过内存淘汰策略来释放空间,避免系统崩溃或性能下降。

一、内存淘汰策略概述
当Redis 实例使用的内存超过 maxmemory 配置限制时,它会根据配置的淘汰策略(maxmemory-policy)决定如何处理新写入的数据以及现有数据。Redis 提供了多种内存淘汰策略,这些策略决定了当内存不足时,哪些键值对会被删除以释放空间。
Redis 支持以下几种主要的内存淘汰策略:
1. noeviction:默认策略,不淘汰任何键,一旦达到内存限制,则返回错误给写操作。
2. volatile-lru:从设置了过期时间的键中,尝试移除最近最少使用的键。
3. allkeys-lru:移除所有键中最久未被使用的键,无论是否设置了过期时间。
4. volatile-lfu:从设置了过期时间的键中,移除最少频率使用的键。
5. allkeys-lfu:移除所有键中访问频率最低的键。
6. volatile-random:随机移除设置了过期时间的键。
7. allkeys-random:随机移除任意键。
8. volatile-ttl:从设置了过期时间的键中,优先移除即将过期的键。

原理:当内存不足时,Redis 不会自动淘汰任何键,而是直接返回错误。 适用场景:适用于对数据完整性和一致性要求极高的场景,例如存储重要业务数据的 Redis 实例。在这种情况下,开发者需要通过其他方式(如增加内存、优化数据结构)来避免内存不足的问题。
原理:从所有键中随机选择并淘汰最近最少使用的键。Redis 使用近似 LRU 算法来估算键的使用频率。 适用场景:适用于缓存场景,尤其是数据访问模式符合 LRU 特性的场景。例如,电商网站的热门商品缓存,用户频繁访问的商品会被保留,而长时间未访问的商品会被淘汰。
原理:从设置了过期时间的键中随机选择并淘汰最近最少使用的键。 适用场景:适用于需要对部分数据设置过期时间的场景,例如会话存储。在这种情况下,只有设置了过期时间的键会被淘汰,未设置过期时间的键不会受到影响。
原理:从所有键中随机选择并淘汰。 适用场景:适用于对数据访问模式没有明确规律的场景,或者对数据丢失不敏感的场景。例如,某些临时数据的存储。
原理:从设置了过期时间的键中随机选择并淘汰。 适用场景:适用于需要对部分数据设置过期时间的场景,但数据访问模式较为随机,无法通过 LRU 或 LFU 策略有效淘汰。
原理:从设置了过期时间的键中淘汰即将过期的键。 适用场景:适用于需要优先淘汰即将过期数据的场景。例如,日志存储系统中,旧日志的过期时间较短,可以优先被淘汰。
原理:从所有键中随机选择并淘汰最近最少频繁使用的键。Redis 使用近似 LFU 算法来估算键的使用频率。 适用场景:适用于数据访问模式符合 LFU 特性的场景。例如,某些热点数据会被频繁访问,而冷数据会被淘汰。
原理:从设置了过期时间的键中随机选择并淘汰最近最少频繁使用的键。 适用场景:适用于需要对部分数据设置过期时间的场景,且数据访问模式符合 LFU 特性。

三、内存淘汰策略的底层实现
LRU 链表:每个键值对都维护一个 LRU 链表,记录键的访问时间。
采样淘汰:当需要淘汰键时,Redis 会从链表中随机采样几个键,选择其中 LRU 的键进行淘汰。
2. LFU 算法的实现
LFU 计数器:每个键值对维护一个 LFU 计数器,记录键的访问频率。
衰减机制:LFU 计数器会随着时间衰减,以模拟键的使用频率变化。
随机淘汰策略的实现非常简单,Redis 会从所有键中随机选择一个键进行淘汰。

四、内存淘汰策略的性能与优化
1. 性能分析
LRU 和 LFU 的近似实现:Redis 的 LRU 和 LFU 算法是近似的,通过采样和计数器来估算键的使用频率。这种近似实现虽然牺牲了一定的准确性,但显著提高了性能。
随机淘汰的性能:随机淘汰策略的性能较高,因为其算法简单,不需要维护额外的数据结构。
2. 优化建议
选择合适的淘汰策略:根据数据访问模式和业务需求选择合适的淘汰策略。例如,缓存场景优先选择 LRU 或 LFU,会话存储优先选择 volatile-lru。
合理设置过期时间:对于需要设置过期时间的键,合理设置过期时间可以减少不必要的淘汰操作。
监控内存使用:通过 Redis 提供的监控工具(如 INFO 命令)实时监控内存使用情况,及时调整淘汰策略或优化数据结构。
结合持久化策略:对于重要数据,可以结合 Redis 的持久化策略(如 RDB 或 AOF)来确保数据的持久性。






