Redis缓存满了咋办?什么叫近似LRU算法?为啥不使用真实LRU?

Redis缓存满了怎么办?

那还用说吗,满了就删除一些旧数据不就有空间了嘛。只是不能瞎删,要遵循策略删。由此,就产生了下图所示的Redis内存淘汰策略:

b4da10f6bf174055aca705570416cfd9.png 

下面详细介绍一下Redis使用的LRU算法(近似)。

近似LRU算法

什么叫LRU算法呢?

LRU的全称是Least Recently Used,也就是 最近最少使用 策略,判断数据最近被使用的时间,距离目前时间最远的数据优先被淘汰,是根据访问时间来更改链表顺序从而实现缓存淘汰的算法。它的核心思想是:如果该数据最近被访问,那么将来被访问的几率也很高。

顺带一提LFU算法:全称是 Least Frequently Used,即 最近最不经常使用策略,在一段时间内,数据被使用频率最少的,优先被淘汰。

LRU强调的是访问时间,LFU强调的是访问频率。

为什么Redis使用的是近似LRU?

究其原因,最为关键的一点是:LRU算法需要用链表管理所有的数据,会造成大量额外的空间消耗。

除此之外,大量的节点被访问就会带来频繁的链表节点移动操作,从而降低了Redis性能。

经常使用的数据在链表的头部,冷数据在尾部,一旦链表容量不够(缓存空间满了),执行删除尾部策略。

所以Redis对该算法做了简化,Redis是通过对少量的key采样,然后淘汰样本数据中最久没有被访问过的key。这就意味着 Redis 很有可能无法淘汰数据库最久访问的数据。

Redis为了实现近似LRU算法,给每个key额外增加了一个24bit的字段,用来存储该key最后一次被访问的时间。

当然Redis 的LRU 算法可以更改样本数量来调整算法的精度,使其更加接近真实的LRU算法,同时又避免了内存的消耗,因为每次只需要采样少量样本,而不是缓存中所有的数据

Redis 3.0对近似LRU的优化

Redis 3.0对近似LRU算法进行了一些优化。新算法会维护一个候选池(大小为16),池中的数据根据访问时间进行排序,第一次随机选取的key都会放入池中,随后每次随机选取的key只有在访问时间小于池中最小的时间才会放入池中,直到候选池被放满。当池放满后,如果有新的key需要放入,则将池中最后访问时间 最大(最近被访问)的移除。当需要淘汰的时候,则直接从池中选取最近访问时间最小(最久没被访问 )的key淘汰掉就行。也就是池中维护的是要被淘汰的数据

 

 

 

 

### Redis LRU 内存淘汰机制的工作流程解释 Redis 是一种高性能的键值存储系统,其内存管理依赖于多种淘汰策略来处理有限的内存资源。其中,LRU(Least Recently Used,最近最少使用)是一种常见的内存淘汰算法,在 Redis 中被广泛采用。 当客户端向 Redis 发送写入请求(如 `SET` 命令),可能导致内存占用超出预设的最大阈值 `maxmemory`。此时,Redis 将依据配置好的淘汰策略自动清理部分数据以释放空间[^3]。以下是 LRU 算法Redis 内存管理中的具体工作流程: #### 1. **内存检查** 每当有新的数据写入时,Redis 都会对当前内存使用情况进行检测。如果发现内存用量超过了设定的上限 `maxmemory`,则触发淘汰过程。 #### 2. **候选 Key 的选取** 为了实现高效的淘汰操作,Redis会遍历整个数据库去寻找最常用的 Key,而是采用了采样方法。默认情况下,它会随机抽取一组 Key,并从中挑选出访问时间最早的 Key 进行删除[^1]。这种近似LRU 方法虽然是绝对精确,但在性能和准确性之间取得了良好的平衡。 #### 3. **Key 访问计数更新** 对于每次读取或写入某个 Key,Redis 都会在内部记录该 Key 的最后一次访问时间戳。这些时间戳用于后续判断哪些 Keys 属于“最近未使用的”。值得注意的是,Redis 使用了一种优化版的时间跟踪方式——通过逻辑钟表而非实际时间戳,从而减少计算开销。 #### 4. **淘汰与回收** 一旦选定了待淘汰的目标 Keys 后,Redis 即可安全地将其移除并腾出相应大小的空间给新到来的数据项。需要注意的一点是,某些特殊类型的 Values (例如大对象或者压缩列表)可能占据更多物理 RAM 资源;因此即使只删掉少量几个这样的 keys ,也可能显著缓解整体压力状况。 此外还需注意一点关于生产环境下的注意事项:在线上运行期间随意更改淘汰政策可能会引起全量结构重组现象发生,这是目前版本redis架构下难以承受的操作成本之一所以建议谨慎对待此类调整动作除非必要否则保持初始设置变即可获得较好效果[^2]. ```python # 示例代码展示如何模拟简单的LRU缓存清除逻辑 class LRUCache: def __init__(self, capacity): self.cache = {} self.order = [] self.capacity = capacity def get(self, key): if key in self.cache: # 更新访问顺序 self.order.remove(key) self.order.append(key) return self.cache[key] else: return None def put(self, key, value): if key not in self.cache and len(self.cache) >= self.capacity: # 移除最早插入的元素 oldest_key = self.order.pop(0) del self.cache[oldest_key] # 插入/更新数据 self.cache[key] = value if key in self.order: self.order.remove(key) self.order.append(key) cache = LRUCache(2) cache.put('a', 1) cache.put('b', 2) print(cache.get('a')) cache.put('c', 3) # 'b' 应被淘汰 print(cache.get('d')) # 返回None因为'd'存在 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值