redis-过期与内存淘汰机制解析
Redis的过期与淘汰策略是它作为一种高性能缓存和数据存储的关键特性之一。这些策略帮助Redis管理存储在内存中的数据,以确保内存资源得以有效利用,同时保持数据的实效性。
过期:管理数据的生命周期
设置过期时间
Redis允许你为每个键设置一个过期时间(Time To Live,TTL
),以确保数据在特定时间内自动失效。一旦数据过期,Redis将自动删除它,释放内存。这对于缓存非常有用,因为你可以设置缓存的数据在一段时间后自动更新,以确保数据的新鲜度。
我们通过以下指令给指定key的缓存设置过期时间,如果都没设置过期时间, key 将一直存在,直到我们使用 Del 的命令明确删除掉。
# 缓存时间过期命令,参考如下
EXPIRE key seconds [ NX | XX | GT | LT]
Redis 7.0 开始,EXPIRE 添加了 NX、XX和GT、LT 选项,分别代表不同的过期设置方式
- NX:仅当Key没有过期时设置过期时间
- XX:仅当Key已过期时设置过期时间
- GT:仅当新到期时间大于当前到期时间时设置到期时间
- LT:仅当新到期时间小于当前到期时间时设置到期时间
其中,GT、LT和NX选项是互斥的,下面是官方的测试用例:
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis> SET mykey "Hello World"
"OK"
redis> TTL mykey
(integer) -1
redis> EXPIRE mykey 10 XX
(integer) 0
redis> TTL mykey
(integer) -1
redis> EXPIRE mykey 10 NX
(integer) 1
redis> TTL mykey
(integer) 10
两种过期数据的删除方式
我们前面说过,Redis删除过期数据主要通过以下两个方式,我们一个个来看:
- 惰性删除: 当客户端请求查询键时,Redis会检查键是否过期,如果过期则删除。这将过期数据的删除主动权交给了访问请求的客户端,但可能导致过期数据长时间存在,直到有访问请求。
- 定期删除:通过定时任务,定期选取部分数据删除。Redis使用定时任务定期删除过期数据,执行频率由
redis.conf
配置文件中的hz参数控制。每次任务会随机抽取设置了过期时间的键,并检查是否过期,然后删除。这种方式保证了过期数据的及时清理。
定时删除的流程
Redis 默认每 1 秒运行 10 次,也就是每 100 ms 执行一次,每次随机抽取一些设置了过期时间的 key(这边注意不是检查所有设置过期时间的key,而是随机抽取部分),检查是否过期,如果发现过期了就直接删除。
# 代表每1s 运行 10次
hz 10
该定时任务的具体流程如下:
- 定时serverCron方法去执行清理,执行频率根据redis.conf中的hz配置的值
- 执行清理的时候,不是去扫描所有的key,而是去扫描所有设置了过期时间的key(redisDb.expires)
- 如果每次去把所有过期的key都拿过来,那么假如过期的key很多,就会很慢,所以也不是一次性拿取所有的key
- 根据hash桶的维度去扫描key,扫到20(可配)个key为止。假如第一个桶是15个key ,没有满足20,继续扫描第二个桶,第二个桶20个key,由于是以hash桶的维度扫描的,所以第二个扫到了就会全扫,总共扫描35个key
- 找到扫描的key里面过期的key,并进行删除
- 删除完检查过期的 key 超过 25%,继续执行4、5步
内存淘汰机制:释放内存空间
如果Redis的内存使用超出了配置的最大内存限制,它会根据配置的内存淘汰策略来删除键以释放内存。常见的内存淘汰策略包括:
Redis的内存淘汰策略是为了应对内存资源有限的情况下,合理地选择哪些数据需要从内存中移除,以确保Redis的性能和稳定性。以下是Redis内存淘汰策略:
策略名称 | 描述 | 特点 |
---|---|---|
No Eviction (无淘汰) | 不会自动移除任何数据,所有写操作返回错误。需要应用程序负责内存管理。 | 适用于数据不可丢失的场景,但需要应用程序主动处理内存不足。 |
VolatileLRU (带过期时间的LRU) | 选择带过期时间的数据中最近最少被使用的数据进行淘汰。 | 主要用于处理具有过期时间的数据。主要适用于具有冷热数据明显的场景比如电商平台的冷热数据、餐饮平台美食外卖 |
VolatileLFU (带过期时间的LFU) | 选择带过期时间的数据中最不经常使用的数据进行淘汰。 | 基于不经常使用的原则来淘汰带过期时间的数据。LRU算法的不足之处在于,一个本身很少被访问的key,只是刚刚被访问了1次,就被认为是最近有使用的热点数据,导致短时间内不会被淘汰。 而LFU弥补了这个不足,LFU(Least Frequently Used) 淘汰策略会根据key的最近访问频率进行淘汰,解决上面说的这个不足。 |
VolatileTTL (带过期时间的TTL) | 根据键的剩余时间选择淘汰数据,越快过期的数据优先淘汰。 | 用于按照过期时间来淘汰数据的场景。 |
AllKeysLRU (最近最少使用) | 当内存不足时,选择最近最少被使用的数据进行淘汰。 | 试图保留最常用的数据,适用于缓存中常用数据较多的场景。 |
AllKeysLFU (最不经常使用) | 选择最不经常使用的数据进行淘汰。 | 适用于按照数据的使用频率来淘汰数据的场景。 |
Random (随机淘汰) | 随机选择数据进行淘汰,不考虑使用频率或过期时间。 | 不太可控,但在某些情况下可以工作得很好。 |
Approximated LRU (近似LRU) | 尝试以较低的计算成本近似LRU,使用HyperLogLog 来估算最近最少被使用的键。 | 在降低计算成本的同时近似LRU淘汰,Redis 6.0中引入。 |
总结
Redis的过期与淘汰策略是redis成功的关键因素之一,它们确保了数据的实效性和内存资源的有效利用。过期和内存淘汰机制通常一起使用,以确保Redis始终保持在可控的内存占用下。选择正确的策略可以确保Redis在内存有限的情况下仍然能够提供高性能和可用性。
转载自:https://juejin.cn/post/7276630249546629159