Redis - 设置过期时间、过期策略、内存淘汰策略教程
作者:hangge | 2024-12-03 09:08
一、设置过期时间
1,设置过期时间命令
(1)设置 key 过期时间的命令一共有 4 个:
(2)当然,在设置字符串时,也可以同时对 key 设置过期时间,共有 3 种命令:
典型应用场景:手机验证码。我们平时在登录或者注册的时候,手机会接收到一个验证码,上面会提示验证码的过期时间,过了这个时间之后这个验证码就不能用了。
#设置 key 在 n 秒后过期,比如 expire key 100 表示设置 key 在 100 秒后过期 expire <key> <n> #设置 key 在 n 毫秒后过期,比如 pexpire key2 100000 表示设置 key2 在 100000 毫秒(100 秒)后过期 pexpire <key> <n> #设置 key 在某个时间戳(精确到秒)之后过期,比如 expireat key3 1655654400 表示在时间戳 1655654400 后过期 expireat <key> <n> #设置 key 在某个时间戳(精确到毫秒)之后过期,比如 pexpireat key4 1655654400000 表示在时间戳 1655654400000 后过期(精确到毫秒) pexpireat <key> <n>
(2)当然,在设置字符串时,也可以同时对 key 设置过期时间,共有 3 种命令:
set <key> <value> ex <n> # 设置键值对的时候,同时指定过期时间(精确到秒); set <key> <value> px <n> # 设置键值对的时候,同时指定过期时间(精确到毫秒); setex <key> <n> <valule> # 设置键值对的时候,同时指定过期时间(精确到秒)。
2,取消过期时间
取消 key 的过期时间,则可以使用 PERSIST <key> 命令。
(2)当 key 永久存在的时候,执行 ttl 返回的是-1。当 key 已经被删除了,不存在的时候,执行 ttl 返回的是 -2。
persist key1 # 取消 key1 的过期时间
3,获取剩余的有效时间
(1)使用 ttl 命令可以获取 key 的剩余有效时间:ttl stu:1

(2)当 key 永久存在的时候,执行 ttl 返回的是-1。当 key 已经被删除了,不存在的时候,执行 ttl 返回的是 -2。

二、过期策略
1,基本介绍
(1)我们在 set key 的时候,可以给它设置一个过期时间,当过期时间到达后,Redis 将会执行如下两种过期策略:
- 定期删除:Redis 每隔一段时间(默认是 100ms)会随机检查一些已设置过期时间的键(写死在代码中的,数值固定是 20),然后删除其中已过期的键。这个过期检查操作是定期进行的,它并不是在键到期时立即执行的,因此可能存在一些键过期但仍未被删除的情况。
- 惰性删除:当访问一个带有过期时间的键时,Redis 会先检查该键是否过期。如果过期,Redis 会在访问该键时立即删除它。这就是所谓的惰性删除,因为过期键的删除是在访问时触发的。
提示:随机只是为了保证每个 key 都有一定概率被抽查到。假设说我们在每个 DB 内部都是从头遍历的话,那么如果每次遍历到中间,就没时间了,那么 DB 后面的 key 你可能永远也遍历不到。
(2)Redis 中同时使用了惰性过期和定期过期两种过期策略:
- 假设 Redis 当前存放 30 万个 key,并且都设置了过期时间,如果每隔 100ms 就去检查这全部的 key,CPU 负载会特别高,最后可能会挂掉。
- 因此,redis 采取的是定期删除,每隔 100ms 就随机抽取一定数量的 key 来检查和删除的。
- 但是呢,最后可能会有很多已经过期的 key 没被删除。这时候,redis 采用惰性删除。在你获取某个 key 的时候,redis 会检查一下,这个 key 如果设置了过期时间并且已经过期了,此时就会删除。
2,如何控制定期删除的频率
(1)在 Redis 里面,定期删除的频率可以通过 hz 参数来控制。不过 hz 控制的是所有的后台任务,并不是单独控制这一个定期删除循环。
- 假如说 hz 的值是 N,那么就意味着每 1/N 秒就会执行一次后台任务。举例来说,如果 hz=10,那么就意味着每 100ms 执行一次后台任务。
(2)正常来说,hz 这个值不需要调,即便调整也不要超过 100。
(3)与之相关的是 dynamic-hz 参数。这个参数开启之后,Redis 就会在 hz 的基础上动态计算一个值,用来控制后台任务的执行频率。
三、内存淘汰策略
1,基本介绍
如果定期删除漏掉了很多过期的 key,然后也没走惰性删除。就会有很多过期 key 积在内存内存,直接会导致内存爆掉。为了避免这个问题,Redis 还使用了 8 种内存淘汰策略保护自己。当 Redis 的运行内存已经超过 Redis 设置的最大内存之后,则会使用内存淘汰策略删除符合条件的 key,以此来保障 Redis 高效的运行。
(1)如何设置 Redis 最大运行内存?
- 在配置文件 redis.conf 中,可以通过参数 maxmemory <bytes> 来设定最大运行内存,只有在 Redis 的运行内存达到了我们设置的最大运行内存,才会触发内存淘汰策略。
(2)不同位数的操作系统,maxmemory 的默认值是不同的:
- 在 64 位操作系统中,maxmemory 的默认值是 0,表示没有内存大小限制,那么不管用户存放多少数据到 Redis 中,Redis 也不会对可用内存进行检查,直到 Redis 实例因内存不足而崩溃也无作为。
- 在 32 位操作系统中,maxmemory 的默认值是 3G,因为 32 位的机器最大只支持 4GB 的内存,而系统本身就需要一定的内存资源来支持运行,所以 32 位操作系统限制最大 3 GB 的可用内存是非常合理的,这样可以避免因为内存不足而导致 Redis 实例崩溃。
2,8 种内存淘汰策略
(1)不进行数据淘汰的策略:
(2)在设置了过期时间的数据中进行淘汰的策略:
(3)在所有数据范围内进行淘汰的策略:
- noeviction(Redis 3.0 之后,默认的内存淘汰策略):当内存不足以容纳新写入数据时,不淘汰任何数据,这时如果有新的数据写入,会报错通知禁止写入。但是如果没用数据写入的话,只是单纯的查询或者删除操作的话,还是可以正常工作。
- volatile-random:当内存不足以容纳新写入数据时,从设置了过期时间的 key 中,随机淘汰数据;
- volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的 key 中,根据过期时间进行淘汰,越早过期的优先被淘汰;
- volatile-lru(Redis 3.0 之前,默认的内存淘汰策略):当内存不足以容纳新写入数据时,从设置了过期时间的 key 中使用 LRU(最久未被使用)算法进行淘汰;
- volatile-lfu(Redis 4.0 后新增的内存淘汰策略):当内存不足以容纳新写入数据时,在过期的 key 中,使用 LFU 算法(最少使用)进行删除 key。
- allkeys-random:当内存不足以容纳新写入数据时,从所有 key 中随机淘汰数据。
- allkeys-lru:当内存不足以容纳新写入数据时,从所有 key 中使用 LRU(最久未被使用)算法进行淘汰。
- allkeys-lfu(Redis 4.0 后新增的内存淘汰策略):当内存不足以容纳新写入数据时,从所有 key 中使用 LFU 算法(最少使用)进行淘汰;

3,自定义内存淘汰策略
(1)有时我们需要根据业务的重要性来设计内存淘汰策略。
- 比如说某个服务同时服务于 VIP 用户和普通用户,那么完全可以在缓存触发淘汰的时候,先把普通用户的数据淘汰了。
- 所以可以考虑为每一个键值对绑定一个优先级,每次缓存要执行淘汰的时候,就从先淘汰优先级最低的数据。
(2)上面这个按照优先级来淘汰的策略实现步骤如下:
- 我们在 Redis 上利用有序集合设计了一个控制键值对数量,并且按照优先级来淘汰键值对的机制。这个有序集合是使用数据的优先级来排序的,也就是用优先级作为 score。
- 增加一个键值对就要执行一个 lua 脚本。在这个脚本里面,它会先检测有序集合里面的元素个数有没有超过允许的键值对数量上限,如果没有超过,就写入键值对,再把 key 加入有序集合。如果超过了上限,那么就从有序集合里面拿出第一个 key,删除这个 key 对应的键值对。
- 同时监听 Redis 上的删除事件,每次收到删除事件,就把有序集合中对应的 key 删除。
- 在这个基础上,我可以根据不同的业务特征来计算优先级,从而实现大对象先淘汰、小对象先淘汰、热度低先淘汰等算法。
全部评论(0)