原文地址:https://redis.io/topics/lru-cache

Redis可以用来作缓存,他可以很方便的淘汰(删除)旧数据添加新数据,类似memcached。LRU只是其中的一种置换算法,这篇文章介绍了maxmemory配置命令和LRU算法的一些深入讨论,这里的LRU只是一种近似LRU(并不是严格的把最老的数据淘汰,而是使用随机采样的方式)。从4.0开始Redis引入了一种新的淘汰算法LFU(Least Frequently Used)。

maxmemory配置命令

maxmemory配置命令用来指定Redis存储数据的大小,可以在redis.conf里配置,也可以运行的时候用CONFIG SET配置。比如配置成使用100M内存,配置命令如下

maxmemory 100mb

如果把maxmemory设置成0就是不对内存使用量做限制。在64位系统上默认是设置成0,在32位系统上默认设置成3GB。如果达到了限制内存,会根据配置采取不同的策略,可以给相应的命令返回错误,也可以淘汰旧数据来存入新数据。

淘汰策略

在配置文件里使用maxmemory-policy命令指定淘汰策略,取值如下

  • noeviction:达到限制内存以后再存新数据会返回出错。
  • allkeys-lru:淘汰最近没使用的数据。
  • volatile-lru:在设置了过期值(expire)的数据里淘汰最近没使用的数据。
  • allkeys-random:随机淘汰数据。
  • volatile-random:在设置了过期值(expire)的数据里随机淘汰数据。
  • volatile-ttl:在设置了过期值(expire)的数据里淘汰快要过期的数据。

volatile-lru,volatile-random和volatile-ttl在没有可淘汰的数据的时候也会像noeviction一样返回出错。怎样选择淘汰策略取决于你的程序,也可以在使用的过程中用INFO命令观察命中率再做调整。一般情况按如下方法选择淘汰策略:

  • 如果所存储的数据访问量成幂律分布的,也就是说一部分数据的访问量明显多于其他数据,那么就使用allkeys-lru。
  • 如果所存储的数据周期访问的,或者被访问的概率大致相同,那么就是用allkeys-random。
  • 如果所存储的数据设置了不同的过期时间,可以用volatile-ttl。

如果在一个redis实例里存储了两种数据(永久数据和带过期时间的数据),使用volatile-lru和volatile-random是比较好的选择。当然更好的办法是把这两种数据分别存在一个redis实例里。给数据设置过期时间是需要消耗内存的,所以使用allkeys-lru会更节省内存。

淘汰数据的过程

  • 客户端请求添加数据。
  • redis检查内存是否超过了maxmemory限制,如果超过了就根据策略淘汰旧数据。
  • 添加客户端要求的添加的数据。

所以内存使用量会一直在maxmemory上下徘徊,如果某个命令要求添加一个很大的数据很可能造成redis使用的内存明显超过了maxmemory限制。

近似LRU算法

redis的LRU没有严格的实现LRU,也就是说redis不是淘汰最佳(最久没访问)的数据。redis会做一个随机采样,淘汰样本里最佳数据。3.0以后redis会使用备选池做淘汰,提升了性能,准确性更高,更接近LRU算法(代码里提升性能很明显,准确率更高这点看不出来,可能官方做统计得出的结论)。可以设置样本大小调整算法的准确率。

maxmemory-samples 5

redis没用真正的LRU实现是因为这正的LRU太消耗内存了,要遍历排序,会慢很多。下图是近似LRU算法和真正的LRU算法的测试对比图

测试的时候先生成一些数据。从第一个数据开始存储,一直到最后一个,所以第一个数据是LRU算法的最佳淘汰对象。最后又添加50%的数据用来淘汰旧数据。上面的三个色带分别是:

  • 浅灰色是淘汰的数据
  • 灰色是没有淘汰的数据
  • 绿色是新添加的数据。

理论上最先添加的一半数据应该淘汰,redis的LRU算法只是概率性的淘汰这些旧数据。可以看出来在maxmemory-samples设置成5的时候3.0版本比2.8版本更精确(相对来说更接近理论值)。maxmemory-samples设置成10的时候3.0版本已经相对接近理论值了。

LRU只是预测将来一段时间的数据访问模型,如果你的数据成幂律分布redis的LRU也能非常好的处理这个模型。 redis的LRU和真正的LRU差距非常小甚至没差距。如果想要更接近LRU可以提高样本采集量把maxmemory-samples设置成10。

新的近似LFU模式

从4.0开始redis引入了一个新的淘汰模型LFU(Least Frequently Used)。一些情况下这个模型在命中率上更会准确。LFU会统计数据的使用率,使用率低的会被淘汰,使用率高的留下。LRU会保留最近访问了但是平常访问率很低的数据,风险就是淘汰了一个平常访问率高但是最近没访问的数据。LFU不会存在这样的问题,所以LFU更适用于各种不同的访问模型。LFU策略配置如下:

  • volatile-lfu:在设置了过期时间的数据里使用近似LFU淘汰算法。
  • allkeys-lfu:在所有的数据上使用LFU淘汰算法。

LFU和LRU类似也是一种概率计算,LFU使用一个叫morris counter的概率统计方法,一个数据只使用几个比特。和一个叫过期时间(decay period)的数结合使用。统计值(counter)随着时间减小。LFU也是使用采样的方式淘汰数据。LFU有更多的调整选项,4.0默认的配置

  • 一百万访问量会使统计值(counter)变为最大
  • 衰败期是一分钟

这些是经过测试比较好用的,用户也可以自己设置。配置命令如下:

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

一个比较特殊的用法是衰败期设置成0,每次统计都会衰败,这是个比较少用的方法。指数因子用来指定多大的访问量会是统计值变为最大,统计值范围0-255。指数因子越大需要越多的访问量使统计值变为最大,指数因子越小访问量低的时候分辨率越高。

+--------+------------+------------+------------+------------+------------+
| factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits |
+--------+------------+------------+------------+------------+------------+
| 0 | 104 | 255 | 255 | 255 | 255 |
+--------+------------+------------+------------+------------+------------+
| 1 | 18 | 49 | 255 | 255 | 255 |
+--------+------------+------------+------------+------------+------------+
| 10 | 10 | 18 | 142 | 255 | 255 |
+--------+------------+------------+------------+------------+------------+
| 100 | 8 | 11 | 49 | 143 | 255 |
+--------+------------+------------+------------+------------+------------+

所以指数因子需要在分辨率和高访问之间做一个折中。redis.conf里有更详细的说明。

近似LFU算法

  1. 取一个0到1之间的随机值R
  2. 计算P=1/(old_value*lfu_log_factor+1),这里的old_value就是上面说的counter值。
  3. 当R<P的时候counter加一。

不是学数学的不会证明这个算法,但是看起来这个算法本身不难,也是用的概率的方法,访问量和counter值之间大概是指数关系,用的时候参考上面那个表就行了。

用redis当作LRU缓存的更多相关文章

  1. Redis学习笔记2-使用 Redis 作为 LRU 缓存

    当 Redis 作为缓存使用时,当你添加新的数据时,有时候很方便使 Redis 自动回收老的数据.LRU 实际上是被唯一支持的数据移除方法.Redis 的 maxmemory 指令,用于限制内存使用到 ...

  2. Redis - 作为 LRU 缓存

    一.简介 LRU 实际上是被唯一支持的数据移除方法,同时也是 memcached 默认支持的缓存算法. 二.配置内存大小 在 redis.conf 文件中使用 maxmemory 指令能够配置内存大小 ...

  3. Redis作为lru缓存作用

    当 Redis 作为缓存使用时,当你添加新的数据时,有时候很方便使 Redis 自动回收老的数据.LRU 实际上是被唯一支持的数据移除方法.Redis 的 maxmemory 指令,用于限制内存使用到 ...

  4. redis(7)LRU缓存

    一.LRU简介 LRU是Least Recently Used的缩写,即:最近最少使用. 它是内存管理中的一种页面置换算法,对于在内存中但是又不用的数据块,操作系统会根据哪些数据属于LRU而将其移除内 ...

  5. Redis做LRU缓存

    当Redis用作缓存时,通常可以让它在添加新数据时自动逐出旧数据. 这种行为在开发人员社区中非常有名,因为它是流行的memcached系统的默认行为. LRU实际上只是支持的驱逐方法之一. 本页介绍了 ...

  6. redis文档翻译_LRU缓存

    Using Redis as an LRU cache使用Redis作为LRU缓存 出处:http://blog.csdn.net/column/details/redisbanli.html Whe ...

  7. 动手实现 LRU 算法,以及 Caffeine 和 Redis 中的缓存淘汰策略

    我是风筝,公众号「古时的风筝」. 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面. 那天我在 LeetCode 上刷到一道 LRU 缓存机制的问题, ...

  8. 在我们使用Redis作为一个LRU缓存的时候,怎么做才能更高效

    当用Redis作为一个LRU存储时,有些时候是比较方便的,在你增添新的数据时会自动驱逐旧的数据.这种行为在开发者论坛是非常有名的,因为这是流行的memcached系统的默认行为. LRU实际上只是支持 ...

  9. Redis只作为缓存,不做持久化的配置

    #1.配置缓存内存限制和清理策略 #作为缓存服务器,如果不加以限制内存的话,就很有可能出现将整台服务器内存都耗光的情况,可以在redis的配置文件里面设置: #example: # 限定最多使用1.5 ...

随机推荐

  1. Mybatis源码学习第六天(核心流程分析)之Executor分析(补充)

    补充上一章没有讲解的三个Executor执行器; 还是贴一下之前的代码吧;我发现其实有些分析注释还是写在代码里面比较好,方便大家理解,之前是我的疏忽,不好意思 @Override public < ...

  2. Myeclipse 连接数据库(jdbc)

    1.找到DataBase Explorer,如下图所示: 2.点击下图红框内图标,new 3.进入下图界面 如果是JDBC驱动按下图配置: driver name自己起 url一定要注意:jdbc:m ...

  3. 浅说iOS二维码的那些事儿

    二维码需要用到 Quartz 2D 一般是三步走~1导入CoreImage框架,编写字符串转二维码图;2渲染二维码;3显示二维码. 导入头文件 #import <CoreImage/CoreIm ...

  4. Django request

    ''' 1.HttpRequest.GET 一个类似于字典的对象,包含 HTTP GET 的所有参数.详情请参考 QueryDict 对象. 2.HttpRequest.POST 一个类似于字典的对象 ...

  5. lombok使用(给自己看的,只为不要忘记自己用过的技术)

    如何使用? 一.1)eclipse使用方法 1. 从项目首页下载lombok.jar 2. 双击lombok.jar, 将其安装到eclipse中(该项目需要jdk1.6+的环境) 2)idea使用方 ...

  6. mxgraph浅入

    mxgraph浅入 参考文献:https://www.cnblogs.com/xuxg/articles/3246206.html 1.了解 (1)如何判断需要引入mxgraph产品:过程图.工作流和 ...

  7. Flutter集成环信IM,发送图片之后渲染conversation.loadMoreMsgFromDB报path为空

    这时会报错,结果如下: 只需在em_message_body下修改如图path为空即可

  8. Python2.7集成scrapy爬虫错误解决

    运行报错: NotSupported: Unsupported URL scheme 'https':.... 解决方法:降低对应package的版本 主要是scrapy和pyOpenSSL的版本 具 ...

  9. JVM性能调优(2) —— 垃圾回收器和回收策略

    一.垃圾回收机制 1.为什么需要垃圾回收 Java 程序在虚拟机中运行,是会占用内存资源的,比如创建的对象.加载的类型数据等,而且内存资源都是有限的.当创建的对象不再被引用时,就需要被回收掉,释放内存 ...

  10. 帮你理清React的生命周期

    这是一个从印记中文 | react官方文档提取总结的,算是帮自己理清并且强化记忆React的生命周期,以便以后编写组件的时候能够有更清晰的思路.本文如有纰漏,欢迎指正 整体上来讲,React生命周期分 ...