【原】Redis-LRU缓存
Redis高级篇
-
Redis-LRU缓存
将Redis作为缓存使用时,有时添加新数据时,旧数据是很难被清空的。
LRU(Least Recently Used) 近期最少使用算法是常用算法之一。
最大内存配置
- 最大内存配置是为数据集配置的最大可用内存。可在redis.conf文件中配置,也可以用命令CONFIG SET来配置。
例如,为了配置100m的最大内存,在redis.conf文件中配置:
maxmemory 100mb - 如果maxmemory设置为0,表明没有内存限制,这是64bit系统默认采用的。32bit系统默认为3GB。
- 当指定内存使用完时,需要采取一定的policies来应对。Redis会直接报错或清除旧数据给新数据腾出空间。
Evition policies(回收策略)
用maxmemory-policy属性来配置回收策略。
回收策略如下:
- noenviction:不清除数据,只是返回错误,这样会导致浪费掉更多的内存,对大多数写命令(DEL 命令和其他的少数命令例外)
- allkeys-lru:从所有的数据集中挑选最近最少使用的数据淘汰,以供新数据使用
- volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰,以供新数据使用
- allkeys-random:从所有数据集中任意选择数据淘汰,以供新数据使用
- volatile-random:从已设置过期时间的数据集中随机选择数据淘汰,以供新数据使用
- volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰,优先清除存活时间较短的keys,以供新数据使用
当 cache 中没有符合清除条件的 key 时,回收策略 volatile-lru, volatile-random 和volatile-ttl 将会和策略 noeviction 一样直接返回错误。
选择正确的回收策略是很重要的,取决于你的应用程序的访问模式。但是,你可以在程序运行时重新配置策略,使用 INFO 命令输出来监控缓存命中和错过的次数,以调优你的配置。
通用规则如下:
- 如果期望用户请求呈现幂律分布(power-law distribution),也就是,期望一部分子集元素被访问得远比其他元素多时,可以使用allkeys-lru策略。在你不确定时这是一个好的选择。
- 如果期望是循环周期的访问,所有的键被连续扫描,或者期望请求符合平均分布(每个元素以相同的概率被访问),可以使用allkeys-random策略。
- 如果你期望能让 Redis 通过使用你创建缓存对象的时候设置的TTL值,确定哪些对象应该是较好的清除候选项,可以使用volatile-ttl策略。
当你想使用单个Redis实例来实现缓存和持久化一些键,allkeys-lru和volatile-random策略会很有用。但是,通常最好是运行两个Redis实例来解决这个问题。
另外值得注意的是,为键设置过期时间需要消耗内存,所以使用像allkeys-lru这样的策略会更高效,因为在内存压力下没有必要为键的回收设置过期时间。
回收过程
理解回收策略的处理过程是非常重要的,如下:
- 一个客户端运行一个新命令,添加了新数据。
- Redis检查内存使用情况,如果大于maxmemory限制,根据策略来回收键。
- 一个新的命令被执行,如此等等。
LRU算法
Redis的LRU算法不是一个严格的LRU实现。这意味着Redis不能选择最佳候选键来回收。相反,Redis 会尝试执行一个近似的LRU算法,通过采样一小部分键,然后在采样键中回收最适合(拥有最久访问时间)的键。
然而,从Redis3.0开始,算法被改进为维护一个回收候选键池。这改善了算法的性能,使得更接近于真实的LRU算法的行为。Redis的LRU算法有一点很重要,你可以调整算法的精度,通过改变每次回收时检查的采样数量。
Redis中LRU算法比较重要的是你能通过改变回收策略中的样本数量来调整算法的精确度。它是通过下面的配置来实现的。
maxmemory-samples 5
Redis没有使用真实的LRU实现的原因,是因为这会消耗更多的内存。然而,近似值对使用Redis的应用来说基本上也是等价的。
LRU只是一个预测模型用来指定键在未来如何被访问。另外,如果你的数据访问模式非常接近幂律,大多数的访问都将集中在一个集合中,LRU近似算法将能处理得很好。
在模拟实验的过程中,我们发现使用幂律访问模式,真实的LRU算法和Redis的近似算法之间的差异非常小,或者根本就没有。然而,你可以提高采样大小到10,这会消耗额外的CPU,来更加近似于真实的LRU算法,看这会不会使你的缓存错失率有差异。
使用CONFIG SET maxmemory-samples