# Redis实战:缓存淘汰策略

在这里插入图片描述

# Redis内存满了该怎么办?

在这里插入图片描述

Redis是一个内存数据库,当Redis使用的内存超过物理内存的限制后,内存数据会和磁盘产生频繁的交换,交换会导致Redis性能急剧下降。所以在生产环境中我们通过配置参数maxmemoey来限制使用的内存大小。

在redis.conf中和缓存淘汰策略相关的有如下2个配置

maxmemory: 设置Redis server可以使用的最大内存容量,一旦超过最大容量,会按照maxmemory-policy配置的策略进行内存淘汰操作

maxmemory-policy: 设置内存淘汰策略,主要有近似lru,近似lfu,ttl和随机淘汰这几种策略

当实际使用的内存超过maxmemoey后,Redis提供了如下几种可选策略。


noeviction:写请求返回错误


volatile-lru:使用lru算法删除设置了过期时间的键值对

volatile-lfu:使用lfu算法删除设置了过期时间的键值对

volatile-random:在设置了过期时间的键值对中随机进行删除

volatile-ttl:根据过期时间的先后进行删除,越早过期的越先被删除


allkeys-lru:在所有键值对中,使用lru算法进行删除

allkeys-lfu:在所有键值对中,使用lfu算法进行删除

allkeys-random:所有键值对中随机删除


我们来详细了解一下lru和lfu算法,这是2个常见的缓存淘汰算法。因为计算机缓存的容量是有限的,所以我们要删除那些没用的数据,而这两种算法的区别就是判定没用的纬度不一样

Redis 的 LRU 和 LFU 算法并不是严格的理论算法,而是近似算法。Redis 为了节省内存和提高性能,会随机抽取几个 key(默认 5 个),然后在这几个 key 里面对比并淘汰最差的那个

# LRU 算法 (Least Recently Used) 最近最少使用

# 核心思想

“如果一个数据最近刚被访问过,那么它接下来的被访问概率也会很高。”LRU 算法关注的是时间长短。它会淘汰那个最久没有被访问过的数据

# 工作原理

你可以把 LRU 想象成一个排队系统:

  1. 每当一个数据被访问(无论是新写入还是被读取),它就会被移到队伍的最前端(队头),表示它最“新鲜”。
  2. 如果有新数据进来,且内存满了,排在最尾端(队尾)的数据就会被无情淘汰。

# 优缺点

优点:非常符合人类的短期记忆和绝大多数业务场景(比如热点新闻、社交媒体动态,刚发出来的往往最火)。

缺点(缓存污染问题):如果突然有人对一批平时根本没人看的“冷门数据”进行了一次性大批量扫描(比如数据库全表扫描),这些冷门数据会瞬间把热点数据挤出队列。而扫描结束后,这些冷门数据再也不会被访问,导致缓存命中率暴跌

# LFU 算法 (Least Frequently Used) 最不经常使用

# 核心思想

“如果一个数据在过去被访问的次数最多,那么它未来的被访问概率也会最高。”LFU 算法关注的是访问频次。它会淘汰那个总访问次数最少的数据。如果两个数据的访问次数一样,再看谁更久没用过

# 工作原理

LFU 给每个数据都配了一个“访问计数器”:

  1. 数据每被访问一次,计数器就 +1。
  2. 当内存满了需要淘汰数据时,LFU 会扫描所有数据,找出计数器数值最小的那个直接删掉。

# 优缺点

优点:能够完美避开 LRU 的“突发性扫描”问题。即便冷门数据被突发扫描了一次,它的计数器也只是 1,依然会优先被淘汰,不会动摇那些访问量成千上万的真正热点数据。

缺点(时效性滞后问题):如果一个数据在过去很长一段时间内特别火(比如去年的爆款新闻),它的计数器被刷到了 10 万。现在它彻底过时了,再也没人看,但由于它的计数值太高,LFU 会长久地把它保留在内存里,霸占空间。

Redis 是如何解决 LFU 缺点的?

Redis 的 LFU 实现非常聪明。它的计数器不仅会随访问而增加,还会随着时间推移自动“衰减”(例如隔一段时间没被访问,计数器就自动减半),从而解决了旧热点数据霸占内存的问题