1.Redis 的过期删除策略
Redis中有很多的键值对数据,其中绝大部分都有过期时间,此时Redis怎么知道那些需要key过期了,那些没有过期呢?
如果全部遍历一遍效率是比较低的,而且存在和 keys *
同样的问题,导致redis服务阻塞。
redis的整体策略是:
- 惰性删除: 假设key过期了,但是并没有及时删除,而是当key被访问的时候先判断一下有没有过期,如果过期就删除并返回nil
- 定期删除: 每次抽取一部分验证过期时间,这个过程要保证足够快才行。
redis默认每隔100ms检查是否有过期的key,有过期key则删除。
注意:redis不是每隔100ms将所有的key检查一次而是随机抽取进行检查( 如果每隔100ms,全部key进行检查,redis直接进去ICU)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。
上述两种策略的效果一般,仍然可能会有很多过期的key占据内存没有及时删除,为此redis还提供了一种内存淘汰策略。
2.Redis中淘汰策略有哪些
Redis将数据保存在内存中, 内存的容量是有限的,如果redis 内存满了超过设置的最大值会怎么样?
127.0.0.1:6379> set aa bb
(error) OOM command not allowed when used memory > 'mахmemотy'.
如果Redis服务器的内存已经全满,现在还需要向Redis中保存新的数据,如何操作,就是缓存淘汰策略:
- noeviction:返回错误(默认)
- allkeys-random:所有数据中随机删除数据
- volatile-random:有过期时间的数据中随机删除数据
- volatile-ttl:删除剩余有效时间最少的数据
- allkeys-lru:所有数据中删除上次使用时间最久的数据
- volatile-lru:有过期时间的数据中删除上次使用时间最久的数据
- allkeys-lfu:所有数据中删除使用频率最少的
- volatile-lfu:有过期时间的数据中删除使用频率最少的
注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕, 如不能达到内存清理的要求,将出现错误信息。
3.Redis淘汰策略详解
3.1 noeviction
默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。
假设我们正在构建一个医疗系统,其中一个关键功能是实时追踪并存储病人的健康数据,例如心跳,血压,血糖等信息。这些健康数据通过各种医疗设备持续收集并实时发送到我们的系统。为了保证快速的数据读写性能,我们选择使用Redis作为这些实时数据的存储介质。
在这个系统中,数据的完整性和可靠性至关重要。我们不能承受任何数据的丢失,因为这可能会对病人的健康产生直接影响。如果Redis内存达到上限,我们的偏好是停止写入新数据,而不是淘汰已有数据。因为已有数据可能被其他系统组件使用,或者医生正在查看和分析这些数据。所以,在这种情况下,我们应该选择Redis的noeviction淘汰策略。
noeviction策略表示当内存不足以容纳新写入数据时,新的写操作会被拒绝,Redis会返回错误。这样,我们可以保证已有数据的安全,同时系统开发者或运维人员也会得到明确的信号去增加Redis的内存,或者寻找其他的解决方案。
所以,在任何对数据的完整性和可靠性有严格要求,不能接受任何形式数据丢失的场景中,我们都应该选择noeviction作为Redis的内存淘汰策略。
3.2 allkeys-lru
当内存不足以容纳新写入数据时,从所有key中使用LRU(最近最少使用)算法进行淘汰。
假设我们正在运行一个大规模的电子商务网站,该网站拥有数百万的商品。对于每一个商品,我们都会在Redis中存储一份详细信息,包括价格,库存,图片,描述等。
由于商品的数量庞大,我们的Redis实例可能无法将所有商品信息都保存在内存中。同时,我们希望为用户提供快速的商品查询服务。这就需要我们在Redis内存达到上限时,能够智能地选择淘汰部分数据,以便为新的数据腾出空间。
在这种情况下,我们可以选择allkeys-lru策略。allkeys-lru策略会在内存不足以容纳新数据时,先淘汰最长时间未被使用的数据。这意味着那些经常被查询的商品(热门商品)的信息会被保留在内存中,而那些很少被访问的商品(冷门商品)的信息则有可能被淘汰。
allkeys-lru策略的选择,可以帮助我们优化商品的查询性能,因为大部分用户的查询会集中在一部分热门的商品上。尽管我们无法将所有商品的信息都保存在内存中,但是通过allkeys-lru策略,我们可以保证大部分用户查询时能够直接从内存中获取商品信息,提供快速的查询服务。
同时,冷门商品信息的淘汰并不会影响我们的业务,因为一旦用户查询的商品信息在Redis中不存在,我们的系统可以从后端数据库中获取,然后再存入Redis。这样,即使某些商品信息被淘汰,我们也能保证数据的完整性,同时提供良好的用户体验。
3.3 volatile-lru
当内存不足以容纳新写入数据时,从设置了过期时间的key中使用LRU(最近最少使用)算法进行淘汰
假设你正在运行一个新闻网站,其中包括实时新闻,特色文章和评论等各种信息。为了提升用户体验,你使用Redis作为缓存层,暂存这些信息。
在这个例子中,有两类主要的数据:
-
实时新闻:这类数据的生命周期很短,新闻发布后的一段时间内访问量最高,之后访问量会显著下降。因此,你可能会为这些新闻设置一个较短的过期时间,比如15分钟。
-
特色文章和评论:这类数据的生命周期较长,用户可能在一段较长的时间内反复访问。因此,你可能会为这些数据设置一个较长的过期时间,比如24小时,或者干脆不设过期时间。
在这种情况下,如果Redis的内存空间不足,最好使用volatile-lru策略。这个策略会优先淘汰那些已经设定了过期时间(也就是说,会自动淘汰的)且最近最少使用的键。
这样,那些访问量减少的实时新闻会被优先淘汰,从而腾出空间用于存储新发布的新闻或其他数据。而那些经常被访问的特色文章和评论则会被尽可能地保留在内存中。
总的来说,volatile-lru策略在这种情况下可以更好地利用有限的内存资源,同时提供更好的用户体验。
3.4 allkeys-random
当内存不足以容纳新写入数据时,从所有key中随机淘汰数据。
假设你正在运行一个大规模的实时在线拍卖平台,用户可以随时对商品进行出价。你使用Redis作为缓存层,暂存各种类型的数据,包括商品信息、用户出价记录、实时竞拍排名等。这些数据在某些时候都非常重要,但都没有明确的过期时间。
由于拍卖的动态性和实时性,对所有数据的访问频率和模式都无法预测,即每个键可能在任何时候都可能被访问。且由于业务特性,新旧数据在功能上的价值差异并不大,也就是说,对用户来说,新旧数据的重要性是一致的。
在这种场景下,如果Redis的内存空间不足,你可能会选择allkeys-random策略。这个策略会在所有的键中随机选择一个键进行淘汰,它并不关心这个键是否设置了过期时间,也不关心这个键被访问的频率或者时间。
在这个场景中,allkeys-random提供了一种简单但有效的方式来处理内存压力。由于所有数据都有可能被随机淘汰,这就避免了某些数据因为访问频率低而被频繁淘汰,从而在一定程度上保证了所有数据在Redis中的生存机会均等。同时,这种策略的实现和执行效率都相对较高。
但需要注意的是,这种策略可能会导致一些重要数据的意外丢失,因此,在选择使用这种策略时,你需要确保应用可以容忍这种数据丢失,或者有其他机制(如持久化或备份)来防止数据丢失带来的影响。
3.5 volatile-random
内存不足以容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据。
假设你正在管理一个新闻推荐系统。系统的目标是将新闻以及相关的元数据(例如文章标签,作者信息等)缓存起来,以便更快地为用户提供服务。你希望为每篇文章设置一个过期时间,因为新闻的新鲜度是关键,而且新闻的周期性使得过期时间设定成为可能。有些新闻可能在发布后的几个小时或一天内非常热门,但之后可能就不再吸引用户的关注。
在这种情况下,你可能会选择 volatile-random 策略。这种策略会从那些已设置过期时间的键中随机选择一个进行删除,这就确保了那些重要的、永久的数据(比如用户账户信息、系统设置等)不会被删除。
使用 volatile-random 策略有几个好处:
-
volatile-random 有助于保持新闻内容的新鲜性。因为这种策略会随机地从已设置过期时间的键中选择一个进行删除,这就意味着那些过时的或不再相关的新闻更有可能被删除。
-
这种策略也可以提供一种权衡,防止所有新闻在内存不足时被一次性全部删除,因为它是随机选择的。
但是,需要注意的是,volatile-random 策略并不考虑键被访问的频率或者时间。如果你的系统中某些新闻比其他的更热门,那么你可能需要选择不同的淘汰策略,比如 volatile-lru。
3.6 volatile-ttl
内存不足以容纳新写入数据时,在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰
假设你正在运行一个在线广告系统,这个系统通过为用户展示个性化的广告来产生收益。广告可能来自许多不同的广告商,每个广告商都会有他们自己的广告预算和广告有效期。一旦广告的预算用完,或者广告到达设定的结束日期,这个广告就应该被停止展示。
广告信息可以存储在 Redis 中,并为每个广告设置一个过期时间。这个过期时间可以基于广告的预算消耗速度以及广告的结束日期来设定。在这种情况下,你可能会选择 volatile-ttl 策略。这种策略会优先删除 TTL (Time To Live) 值最小的键,也就是最快过期的键。
使用 volatile-ttl 策略有几个好处:
有效地保证了广告的有效期。因为这个策略会优先删除那些快要过期的广告,这就避免了过期广告被展示出来。
节约内存资源。因为只有设置了过期时间的广告会被考虑删除,所以这种策略可以确保那些仍然有广告预算,还没有到结束日期的广告不会被提前删除。
不过,这种策略可能不适合那些广告展示次数和用户互动频率更高的场景,因为它并不考虑这些因素,可能会删除一些用户互动率很高的广告。对于这种场景,可能需要选择其他更适合的淘汰策略。
3.7 allkeys-lfu
4.0版本新增,当内存不足以容纳新写入数据时,从所有key中使用LFU算法进行淘汰;
设想你正在管理一个大型电商网站,该网站有成千上万的产品。每一个产品都有各自的详情页,这些页面需要快速地加载并且展示最新的信息,如价格、库存量等。为了提高性能,你决定使用Redis来缓存这些页面的数据。
然而,有一些商品可能经常被查看(例如热销商品),而其他商品可能很少被查看(例如季节性商品或冷门商品)。如果服务器的内存有限,你需要优先保留那些经常被查看的商品信息在内存中,这样可以最大化缓存的效果。
在这种情况下,你可能会选择 allkeys-lfu(Least Frequently Used)淘汰策略。该策略将优先删除那些最少使用的键。当内存达到上限时,Redis会计算每个键的使用频率,并删除使用频率最低的键。
采用 allkeys-lfu 策略的优点包括:
-
它可以确保热门商品的信息在内存中被保留,从而提高了这些页面的加载速度。
-
它可以有效地利用有限的内存资源,将内存用于那些最需要的地方。
然而,allkeys-lfu 策略可能无法处理那些突然变得非常热门的商品。比如,一个商品可能在某个特殊的日子或者活动期间突然变得很热门,但是因为在之前的大部分时间里它的使用频率很低,所以可能会被 allkeys-lfu 淘汰策略删除。因此,在选择 allkeys-lfu 策略时,还需要考虑这种可能的情况。
3.8 volatile-lfu
4.0版本新增,当内存不足以容纳新写入数据时,在过期的key中,使用LFU算法进行删除key。
让我们设想一个在线新闻平台的场景,该平台每天都发布大量的新闻文章。读者可以阅读、评论和分享这些文章。为了提供更快的用户体验,你选择使用Redis来缓存最新和最热门的文章。每篇文章的缓存都有一个预设的过期时间,例如24小时。然而,服务器的内存是有限的,当内存接近上限时,你需要决定哪些数据应该被淘汰。
在这种情况下,你可以选择 volatile-lfu(Least Frequently Used)淘汰策略。此策略仅对设置了过期时间的键进行淘汰,并且优先淘汰那些使用频率最低的键。这意味着热门的文章(即经常被读者阅读的文章)将会被保留在内存中,而不太热门的文章将会被淘汰。
使用 volatile-lfu 策略的优点:
确保热门文章的缓存能够被长时间地保留在内存中,从而提供更快的访问速度。
由于该策略仅对设置了过期时间的键进行淘汰,那些未设置过期时间的重要数据(例如用户的账户信息)将不会被淘汰。
然而,volatile-lfu 策略的缺点是它需要对每个键都设置过期时间。如果有一些键你忘记设置过期时间,那么这些键将永远不会被淘汰,即使内存已经达到了上限。因此,在使用 volatile-lfu 策略时,需要确保所有的键都设置了合理的过期时间。
4.LFU和LRU的比较
LFU(Least Frequently Used,最少使用)和LRU(Least Recently Used,最近最少使用)都是Redis的内存淘汰策略。它们各自有一些特定的使用场景,而是否"更好"取决于具体的应用需求和使用情况。
LRU:LRU策略基于数据的"年龄"或最后访问时间进行淘汰。这种策略认为,如果一个数据在最近一段时间内没有被访问过,那么在将来也不太可能被访问。因此,当内存需要释放时,Redis会选择最长时间未被访问的数据进行淘汰。
LFU:LFU策略则基于数据的使用频率进行淘汰。它认为,如果一个数据的访问频率较低,那么在将来被访问的可能性也较低。因此,当内存需要释放时,Redis会选择访问频率最低的数据进行淘汰。
以下是LRU和LFU的一些优点:
LRU的优点:
- 对于访问模式较为均匀的场景,或者历史访问模式能较好反映未来访问模式的场景,LRU效果较好。因为它能确保最近使用过的数据能够保留在内存中。
LFU的优点:
- 对于访问模式存在明显热点的场景,LFU能更好地保留热点数据,提高缓存命中率。因为它优先淘汰访问频率低的数据。
至于选择哪种策略,需要基于你的应用特性和需求进行考虑。如果你的应用访问模式较为均匀,或者最近访问过的数据有较大可能性在未来被再次访问,那么LRU可能更适合你。如果你的应用访问模式存在明显的热点,那么LFU可能更优。如果你无法确定,你可以在实际环境中对这两种策略进行测试,看哪种策略能提供更高的缓存命中率。
5.Redis淘汰策略配置
5.1. 查看Redis 最大的占用内存
打开redis配置文件, 设置maxmemory
参数,maxmemory
是bytes字节类型, 注意转换
Redis默认内存多少可以用?
在64bit系统下, maxmemory 设置为 0 表示不限制Redis内存使用。 一般推荐Redis 设置内存为最大物理内存的四分之三。
5.2 修改redis 内存配置及淘汰策略
1.配置文件修改
vim redis.conf
# 修改内容如下:
maxmemory 6442450944
修改redis.conf文件中的maxmemory-policy参数来设置淘汰策略。例如,设置淘汰策略为LRU算法可以添加以下配置:
maxmemory-policy allkeys-lru
2.通过命令修改
127.0.0.1:6379> config set maxmemory 104757600
OK
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "104757600"
127.0.0.1:6379> info memory
# Memory
used_memory:1005168
used_memory_human:981.61K
used_memory_rss:9273344
...
评论区