Redis 过期删除
每当我们对一个 key 设置了过期时间时,Redis 会把该 key 带上过期时间存储到一个过期字典中,也就是说「过期字典」保存了数据库中所有 key 的过期时间。
当查询一个 key 时,Redis 首先检查该 key 是否存在于过期字典中:
- 如果不在:则正常读取键值。
- 如果存在:则会获取该 key 的过期时间,然后与当前系统时间进行比对,如果比系统时间大,那就没有过期,否则判定该 key 已过期。
Redis 使用的过期删除策略是「惰性删除+定期删除」这两种策略配和使用。
惰性删除策略
惰性删除策略的做法是:不主动删除过期键,每次从数据库访问 key 时,都检测 key 是否过期,如果过期则删除该 key。
『 优点』
- 每次访问时,才会检查 key 是否过期,只会使用很少的系统资源,节省 CPU 资源。
『 缺点』
- 浪费内存。当一个 key 过期,只要还没有被访问,占用的内存就不会被释放。
定期删除策略
定期删除策略的做法是:每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查,并删除其中的过期key。
定期删除流程:
- 从过期字典中随机抽取 20 个 key。
- 检查这 20 个 Key 是否过期,并删除已经过期的 key。
- 如果本轮检查的已过期 key 的数量,超过 5 个,也就是「已过期 key 的数量」占比「随机抽取 key 的数量」大于 25%,则继续重复步骤 1;如果已过期的 key 比例小于 25%,则停止继续删除过期 key,然后等待下一轮再检查。最大程度节约 CPU 资源。
定期删除是一个循环,为了保证线程循环卡死,定期删除循环流程上限默认不超过 25 ms。
『 优点』
- 通过限制删除执行时长时间和频率,减少删除操作对 CPU 的影响,同时也清除了一部分过期数据。
『 缺点』
- 不容易确定删除操作执行时长和频率。执行太频繁对 CPU 不友好,执行不频繁跟惰性删除没区别,过期 key 占用的内存不能释放。
持久化时处理过期键
RDB 持久化处理过期 key
【RDB 文件生产阶段】
从内存态转化为 RDB 文件时,会对 key 进行过期检查,过期的键不会被保存到新 RDB 文件中,所以过期键不会对新生成的 RDB 文件产生任何影响。
【RDB 文件加载阶段】
分下面两种情况:
- 「主服务器」运行:在载入 RDB 文件时会对文件中保存的键进行检查,过期键「不会」被载入到数据库中。
- 「从服务器」运行:在载入 RDB 文件时,无论 key 是否过期都会载入到数据库中。但在主从复制时,从服务器数据会被清空。
AOF 持久化处理过期 key
【AOF 文件写入阶段】
在以 AOF 持久化的过程中,如果数据库某个过期 key 还没有被删除,AOF 文件会保留此过期 key。然后在过期 key 被删除后,向 AOF 文件中追加一条 DEL 命令显示删除过期 key。
【AOF 重写阶段】
在执行 AOF 重写时,已经过期的 key 不会被保存到重写后的 AOF 文件中。
Redis 内存淘汰
- noeviction:当运行内存超过设置的最大内存后,不淘汰任何数据,而是不再提供服务,直接返回错误。
- volatile-ttl:优先淘汰最早过期的 key。
- allkeys-lru:淘汰「整个键值」中最久未使用的 key。
- allkeys-lfu:淘汰「整个键值」中最少「最近使用频率少」使用的 key。
- volatile-lru:淘汰「设置了过期时间」的 key 中,最久未使用的 key。
- volatile-lfu:淘汰「设置了过期时间」的 key 中,最少「最近使用频率少」使用的 key。
- allkeys-random:「整个键值」中随机淘汰任意键值。
- volatile-random:「设置了过期时间」的 key 随机淘汰。