Redis 的「内存淘汰策略」和「过期删除策略」,很多小伙伴容易混淆,这两个机制虽然都是做删除的操作,但是触发的条件和使用的策略都是不同的。
今天就跟大家理一理,「内存淘汰策略」和「过期删除策略」。
发车!
过期删除策略
Redis 是可以对 key 设置过期时间的,因此需要有相应的机制将已过期的键值对删除,而做这个工作的就是过期键值删除策略。
如何设置过期时间?
先说一下对 key 设置过期时间的命令。 设置 key 过期时间的命令一共有 4 个:
expire <key> <n> pexpire <key> <n> expireat <key> <n> pexpireat <key> <n>
当然,在设置字符串时,也可以同时对 key 设置过期时间,共有 3 种命令:
set <key> <value> ex <n> set <key> <value> px <n> setex <key> <n> <valule>
如果你想查看某个 key 剩余的存活时间,可以使用 TTL <key>
命令。
# 设置键值对的时候,同时指定过期时间位 60 秒 > setex key1 60 value1 OK # 查看 key1 过期时间还剩多少 > ttl key1 (integer) 56 > ttl key1 (integer) 52
如果突然反悔,取消 key 的过期时间,则可以使用 PERSIST <key>
命令。
# 取消 key1 的过期时间 > persist key1 (integer) 1 # 使用完 persist 命令之后, # 查下 key1 的存活时间结果是 -1,表明 key1 永不过期 > ttl key1 (integer) -1
如何判定 key 已过期了?
每当我们对一个 key 设置了过期时间时,Redis 会把该 key 带上过期时间存储到一个 过期字典 (expires dict)中,也就是说「过期字典」保存了数据库中所有 key 的过期时间。
过期字典存储在 redisDb 结构中,如下:
typedef struct redisDb { dict *dict; /* 数据库键空间,存放着所有的键值对 */ dict *expires; /* 键的过期时间 */ .... } redisDb;
过期字典数据结构结构如下:
- 过期字典的 key 是一个指针,指向某个键对象;
- 过期字典的 value 是一个 long long 类型的整数,这个整数保存了 key 的过期时间;
过期字典的数据结构如下图所示:
字典实际上是哈希表,哈希表的最大好处就是让我们可以用 O(1) 的时间复杂度来快速查找。当我们查询一个 key 时,Redis 首先检查该 key 是否存在于过期字典中:
- 如果不在,则正常读取键值;
- 如果存在,则会获取该 key 的过期时间,然后与当前系统时间进行比对,如果比系统时间大,那就没有过期,否则判定该 key 已过期。
过期键判断流程如下图所示:
过期删除策略有哪些?
在说 Redis 过期删除策略之前,先跟大家介绍下,常见的三种过期删除策略:
- 定时删除;
- 惰性删除;
- 定期删除;
接下来,分别分析它们的优缺点。