
一个示例
❓ redis中,set一个值,有效期为 3600 秒,这个值会什么时候释放?
常规理解为,在 3600 秒到期后,redis服务会自动清除,
也就意味着,redis需要有一个机制,每隔一个时间极短的时间段去扫描所有的key,判断是否到期并删除,这种开销是巨大的
过期删除
对于设置了过期时间的 key,删除有两个机制共同管理
✅ 惰性删除(访问时释放)
触发时机:当客户端访问该 key(如执行 GET、TTL、EXISTS 等命令)时。
行为:Redis 检测到该 key 已过期,立即物理删除该 key,释放内存,然后返回 nil。如果没被访问,即使过了 100 秒,key 仍可能留在内存中。
📌 关键点:如果这个 key 过期后再也没有被访问过,它会一直占用内存,直到被其他机制清理。
✅ 定期删除(后台定时释放)
触发条件:Redis 后台每隔 100ms(默认配置)会启动一次(后台任务)定期扫描任务,随机抽取部分带过期时间的 key 检查。
行为:从所有设置了过期时间的 key 中随机抽取 n 个;删除其中已过期的 key;
📌 关键点:这是一个概率性、非实时的清理过程。所以你设置了过期时间的 key 可能在这一轮扫描中,没扫描到,会在以后的任意时间点(比如 10.2s、12s、甚至更久)被清理,取决于是否被抽中。
对于后台任务执行间隔配置为
# 就这一行配置,默认就是 10
hz 10
hz 10代表的含义为:Redis 每秒钟会执行 10 轮"后台定时任务"循环,用来完成以下工作:
- 扫描并清理已过期的 key(这就是我们用到的)。
- 关闭空闲超时的客户端连接。
- 更新 serverCron 里的各类统计信息、触发 AOF 重写/RDB 保存的阈值判断等。
hz的值调的越高,服务负载越大
❓ 还有另外一种场景,当服务器内存使用超过健康阈值时,如何更好的调优?
比如服务器内存 16G,现在 Redis 用了 15.9G 了,在没钱升级配置的情况下,如何保障能够继续 set get 使用
淘汰策略
这里先说明一个参数 # maxmemory <bytes> ,官方说明为
# Set a memory usage limit to the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys
# according to the eviction policy selected (see maxmemory-policy).
#
# If Redis can't remove keys according to the policy, or if the policy is
# set to 'noeviction', Redis will start to reply with errors to commands
# that would use more memory, like SET, LPUSH, and so on, and will continue
# to reply to read-only commands like GET.
意思就是,
设置内存使用限制为指定的字节数。当达到内存限制时,Redis将尝试根据选择的清除策略,删除键;
如果Redis无法根据策略移除键,或策略设置为 **noeviction**,则 Redis 将开始对会占用更多内存的命令(如SET、LPUSH等)返回错误,但只读命令如GET)依旧可以正常使用。
这个解释很清晰了,该配置默认是注释的,也就意味着 Redis 默认允许无限使用内存!!!
在设置了该参数后,可以根据不同种规则来清除一些 redis 的 key,从而降低内存
参数配置示例
# 限制 Redis 最大使用内存为 4GB
maxmemory 4gb
# 或者使用字节
maxmemory 4294967296
换句话来说,当 Redis 设置了 maxmemory 参数后,可选择下面任何一个方式,来优化内存,具体选择哪种(这里面学问大的很,比方说热点数据、不常用数据的取舍),看你自己
| 策略名称 | 说明 | 备注 |
|---|---|---|
noeviction |
默认策略:内存不足时,新写入会报错(OOM command not allowed) | 不淘汰,默认值 |
allkeys-lru |
从所有 key 中淘汰最近最少使用(Least Recently Used)的 key | LRU算法 |
volatile-lru |
从设置了过期时间的 key 中淘汰 LRU key | LRU算法 |
allkeys-lfu |
从所有 key 中淘汰最不经常使用(Least Frequently Used)的 key | LFU算法 |
volatile-lfu |
从设置了过期时间的 key 中淘汰 LFU key | LFU算法 |
allkeys-random |
从所有 key 中随机淘汰 | 随机算法 |
volatile-random |
从设置了过期时间的 key 中随机淘汰 | 随机算法 |
volatile-ttl |
从设置了过期时间的 key 中淘汰剩余生存时间(TTL)最短的 key | TTL优先 |
这里补充个题外话,LRU与LFU算法区别
✅ LRU 最近最少使用的被淘汰。
实现方式:内部可能通过链表的特性,尾部淘汰吧,具体实现不清楚
✅ LFU 最不经常使用的被淘汰。
实现方式:每个 key 有一个访问频率计数器(logc),具体实现不清楚
📌 LFU示例:对于热点数据维度的保护策略
一个 key 每天被访问 100 次(长期热点),LFU 会保留它。
一个 key 只被访问一次,即使是"最近"访问,LFU 也会优先淘汰。
回顾
- 过期删除方式中的
惰性删除与定期删除为两种不同机制,组合起来构成删除机制 - 过期删除机制 和 淘汰策略 两种之间独立运行,互补干涉
- 淘汰策略只有在设置
maxmemory参数,且内存达到该值时才生效 - 目前来说,不支持多种策略同时生效
- 技术不是一尘不变的,Redis 不同版本是有差异的