使用Redis作为LRU缓存

使用Redis作为LRU缓存

当Redis被用作缓存时,通常可以很方便的在你新加数据时自动驱逐老数据。这种行为是为开发者所众所周知的,因为很流行的memcached系统就是干这个的。

LRU其实是仅是被支持的一种驱逐方式。此页涵盖Redis maxmemory指令主题的许多内容,也包含Redis使用的近似LRU算法。

从Redis4.0开始,一个新的LFU(Least Frequently Used)驱逐策略被引入,此将在该文档中的单独区域介绍。

最大内存配置指令

maxmemory配置指令是用于配置Redis使用一个指定数量的内存来存放数据集。可以在配置文件redis.conf里配置此指令,也可以在运行时使用CONFIG SET命令配置此指令。

例如:为了配置一个100MB的最大内存配置指令,如下指令可用于redis.conf文件中:

maxmemory 100mb

将maxmemory设置为0表示不限制内存。这是64位操作系统的默认行为,而32位系统则使用一个隐性的3GB的内存限制。

当指定的内存被达到,可以选择不同的行为,被叫作策略。Redis可以仅仅返回命令错误,但是可能导致更多内存的使用,或者也可以每次新加数据时驱逐老的数据以返回到指定限制以下。

驱逐策略

当maxmemory限制达到时Redis允许的明确行为可以使用maxmemory-policy配置指令配置。

以下是可用的策略:

  • noeviction:最大内存限制到达后,客户端尝试执行命令时,直接返回错误(DEL命令和其他很少部分命令例外)。
  • allKeys-lru:驱逐keys,尝试优先删除最近使用的最少的keys。
  • volatile-lru:驱逐keys,尝试优先删除最近使用的最少的keys,但只在已过期的keys中删除。
  • allKeys-random:随机驱逐keys以便给新添数据腾地方。
  • volatile-random:随机驱逐keys以便给新添数据腾地方,但仅在已过期keys中随机驱逐。
  • volatile-ttl:为了给新增数据腾地方,驱逐已过期的keys,和试图优先驱逐最短生存时间keys。

注:volatile-lru、volatile-random和volatile-ttl策略在如果没有keys可驱逐的时候其行为同noeviction一样。

选择正确的驱逐方式严重依赖于你的应用程序的访问模式。你也可以在程序运行时监控INFO命令输出的缓存命中和失误的数量,在运行时重新配置驱逐策略。

通常规律:

  • 当你预料你的请求符合幂律分布时,选择allkeys-lru,如果你不确定选哪个,选这个也是个较好选择。
  • 如果你的keys是被循环访问的,或者请求的key是均匀分布的,可以选择allkeys-random策略。
  • 如果你想要以过期时间作为衡量key是否要驱逐,选择volatile-ttl策略。

值得注意的是,给key设置过期时间也是花销内存的,所以使用像allkeys-lru这样的策略是内存更高效的,因为它不需要为被驱逐的key设置过期时间。

驱逐进程是怎么工作的

理解驱逐进程是怎么工作的是相当重要的,如下:

  • 一个客户运行一个新的命令,导致更多数的添加。
  • Redis检查内存使用,如果大于最大内存限制,则依据驱逐策略删除keys。
  • 新的命令继续执行等等。

所以我们持续的超过内存限制的边界,然后通过驱逐keys返回到限制以下。

如果一个命令导致许多内存被使用(如一个较大集合间的求并集操作,并且要存放到一个新的key中)一些时间,那么内存限制可能被超出一个明显的数量。

近似LRU算法

Redis LRU算法并不是精确的实现。这表示Redis不能够选出最好的需要驱逐的对象。取而代之的是试图运行一个近似的LRU算法,通过取样一小部分数量的keys,然后在取样的keys中驱逐一个最合适的(最后访问时间最早的)。

但是,从Redis3.0开始,近似LRU算法被提升到可以取出一个供驱逐的池。这提升了算法的性能,使它更近似接近于一个真正的LRU算法的行为。

关于Redis LRU算法重要的是你能够通过改变检查每次驱逐的取样数量来调整算法的精度。此参数被如下控制:

maxmemory-samples 5

Redis不使用真正LUR算法的原因是它花费太多的内存,但是,使用Redis的应用已经几乎相当。

在精确的LRU算法实现中,在老的keys中,前一半要被过期。在Redis LRU算法则以概率过期老的keys。

在Redis3.0中,取样数设置为10时已无限接近于真正的LRU算法实现。

注:LRU算法仅仅是一个预测一个给定的Key未来被访问的可能性的模型。此外,如果你的数据访问械类似于幂律分布,那绝大部分访问都将集中在Redis 近似LRU算法同样能处理的很好的keys集合中。

在模拟环境下,我们发现使用幂律分布规律访问模式时,在真正LRU算法与Redis LRU近似算法的差别是微乎其微的,或者说是几乎不存在的。

为了体验在生产环境下使用不同取样数所造成的差别,可以在运行时使用CONFIG SET maxmemory-samples 命令改变取样数目以便观察。

新的LFU模型

从Redis4.0开始,一个新的叫做最少频率使用驱逐模型是可用的。此模型在某些场景下可能会工作的更好(提供一个更好的命中/失误比率),因为使用LFU Redis将试图追踪所访问目标的频率,以便极少使用的驱逐而经常使用的则有更高机会保留在内存中。

如果一个目标是最近被访问的,但是几乎是未被访问的,是不应该过期的,所以风险是可能驱逐一个将来有很高机会再次被访问的key。LFU不存在这个问题,并且通常对于不同的访问模式适应的更好。

要配置LFU模式,以下策略是可用的:

  • volatile-lfu:使用LFU算法驱逐keys,在过期的keys中驱逐。
  • allKeys-lfu:使用LFU算法驱逐keys。

LFU同LRU近似:它使用一个概率的计数器,叫作Morris counter用于花费很少节节评估第个对象的访问频率,再结合一个衰变期用以计数器减少时间开销:在某些点我们不再考虑keys的访问频繁度,即使他们是老的keys,所以此算法可适用于访问模式的转变。

但是,不像LRU,LFU拥有某些调整参数:例如,低于多快一个频率一个目标将不能被访问?也可以调整Morris counters范围来使算法适用一些特殊用户场景。

默认情况下Redis4.0被配置成:

  • 计数器一百万请求的饱和度。
  • 每分钟衰变计数器。

怎么改变这些参数的说明可以在redis.conf中找到,简单如下:

lfu-log-factor 10
lfu-decay-time 1

衰变时间是以分钟为单位的,设置为0表示第次浏览都衰变,极少使用。
lfu-log-factor详细查看redis.conf。

你可能感兴趣的:(redis)