今天整理一下关于 Redis 的过期策略和淘汰机制,这两个东西看着很像,其实不是一回事儿。
过期策略
我们在使用 Redis 当作缓存时,通常会给 Redis 的 Key 设置一个过期时间,被设置过期时间的 Key 在未过期时可以对其进行读取或更新操作,也可以主动将其删除。当其超过设置的时间后,它将失效。通过它的过期机制,可以完成很多功能,比如计数器复位、token 过期等。
那么,Redis 对已经过期的数据是进行如何处理,或者说是如何删除呢?在 Redis 中有两种策略来删除过期的 Key,分别是 主动删除和 被动删除 两种方式,也有资料称为 定期删除 和 惰性删除。
被动删除(惰性删除)
被动删除也被称为惰性删除,是 Redis 中的 Key 已经过期,但是 Redis 不会主动将其删除,当有客户端访问该过期 Key 时,Redis 对其进行检查,发现其过期则将其删除,并返回 null 给客户端。
主动删除(定期删除)
惰性删除有它的优点,不会浪费太多的系统资源,但是也存在相应的问题,就是已经过期的 Key 如果不再被访问,就不会被删除了,这样会浪费不必要的存储空间。因此 Redis 存在一种主动删除过期 Key 的策略。
主动删除也被称为定期删除,Redis 会定期扫描已经设置了过期时间的 Key,然后从中删除已经过期的 Key。Redis 默认一秒钟完成 10 次这样的扫描,它大概的流程如下:
- 从设定了过期的 Key 中随机抽取 20 个 Key 进行过期检测
- 删除所有已经过期的 Key
- 如果有本次删除的 Key 超过 25%,那么重复第一步
如果有大量的 Key 过期,这样的扫描可能会导致线程卡顿,因此每次扫描的时长最长为 25ms。
以上是 Redis 处理过期 Key 的方案,当 Redis 服务器占用的内存空间超过最大允许内存之后,会触发内存的淘汰策略。
淘汰策略
内存淘汰策略是指 Redis 使用的内存达到或超过其配置的最大内存时触发的一种保护策略,它根据具体的策略来淘汰一些 Key 使得 Redis 可以继续运行。在 Redis 4.0 之后的版本中,Redis 的内存淘汰策略共有 8 种。
- noeviction:内存达到配置的最大内存时,不再接受新增 Key 的操作,它是默认配置
- allkeys-lru:在所有 Key 中,保留最近使用的 Key,删除最近最少使用的 Key
- allkeys-lfu:在所有 Key 中,保留常用的 Key,删除最不常用的 Key
- allkeys-random:在所有 Key 中,随机删除一些 Key
- volatile-lru:在设置了过期时间的 Key 中,删除最近最少使用的 Key
- volatile-lfu:在设置了过期时间的 Key 中,删除最不常用的 Key
- volatile-random:在设置了过期时间的 Key 中,随机删除一些 Key
- volatile-ttl:在设置了过期时间的 Key 中,删除最短剩余生存时间中最不常用的 Key
从上面的策略中可以看出,大体分为两类,分别是 allkeys 和 volatile 两种。allkeys 是所有的 Key,volatile 是设置了过期时间的 Key。在 allkeys 和 volatile 中使用两个淘汰策略是 LRU 和 LFU,即 最近最少使用(确切的是 近似 LRU 算法) 和 最不常用 两种。
小结
过期和淘汰是两回事,过期是对设置过期时间的 Key 进行删除的一种机制,而淘汰是当使用内存超过设置最大内存时触发的一种保护机制,虽然它也会删除一些 Key。上面整理的是关于 Redis 的过期和淘汰的知识点,具体应该怎么设置淘汰策略,官网给出了建议。需要了解 LRU 和 LFU 算法也可以在官网得到具体的说明。