Redis做LRU缓存
当Redis用作缓存时,通常可以让它在添加新数据时自动逐出旧数据。 这种行为在开发人员社区中非常有名,因为它是流行的memcached系统的默认行为。
LRU实际上只是支持的驱逐方法之一。 本页介绍了Redis maxmemory指令的更一般主题,该指令用于将内存使用限制为固定数量,并且它还深入介绍了Redis使用的LRU算法,实际上是精确LRU的近似值。
从Redis 4.0版开始,引入了新的LFU(最不常用,Least Frequently Used)驱逐策略。 本文档的单独部分对此进行了介绍。
Maxmemory配置指令
maxmemory配置指令用于配置Redis为数据集使用指定数量的内存。 可以使用redis.conf文件设置配置指令,或者稍后在运行时使用CONFIG SET命令设置配置指令。
例如,为了配置100兆字节的内存限制,可以在redis.conf文件中使用以下指令。
1 |
maxmemory 100mb |
将maxmemory设置为零会导致无内存限制。 这是64位系统的默认行为,而32位系统使用3GB的隐式内存限制。
达到指定的内存量时,可以在不同的行为中进行选择,称为 策略。 Redis可以只返回可能导致使用更多内存的命令的错误,或者它可以逐出旧数据以便每次添加新数据时返回到指定的限制。
驱逐策略
使用maxmemory-policy配置指令配置达到maxmemory限制时Redis遵循的确切行为。
可以使用以下策略:
- noeviction:当达到内存限制并且客户端尝试执行可能导致使用更多内存的命令时返回错误(大多数写命令,但DEL和一些例外)。
- allkeys-lru:首先尝试删除最近使用较少的(LRU)key,以便为添加的新数据腾出空间。
- volatile-lru:首先尝试删除最近使用较少的(LRU)key,但仅在具有过期设置的key中删除,以便为添加的新数据腾出空间。
- allkeys-random:随机逐出key,以便为添加的新数据腾出空间。
- volatile-random:随机逐出key以便为添加的新数据腾出空间,但只驱逐带有过期集的key。
- volatile-ttl:用过期集驱逐key,并尝试先用较短的生存时间(TTL)驱逐key,以便为添加的新数据腾出空间。
如果没有用于驱逐匹配先决条件的key,则volatile-lru,volatile-random和volatile-ttl策略的行为类似于noeviction。
根据应用程序的访问模式选择正确的驱逐策略很重要,但是您可以在应用程序运行时在运行时重新配置策略,并使用Redis INFO输出监视缓存未命中和命中的数量,以便调整。
一般来说,作为经验法则:
- 当您期望在请求的流行度中使用幂律分布时,使用allkeys-lru策略,也就是说,您希望访问元素的子集的频率远远高于其他元素。 如果您不确定,这是一个很好的选择。
- 如果您有连续扫描所有键的循环访问,或者您希望分布均匀(所有元素可能以相同的概率访问),请使用allkeys-random。
- 如果您希望能够在创建缓存对象时通过使用不同的TTL值向Redis提供有关到期的最佳候选者的提示,请使用volatile-ttl。
当您希望使用单个实例进行缓存并拥有一组持久key时,volatile-lru和volatile-random策略非常有用。 但是,运行两个Redis实例来解决此类问题通常更好。
还值得注意的是,为key设置过期时间也有内存成本,因此使用像allkeys-lru这样的策略可以提高内存效率,因为在内存压力下不需要为key设置过期。
驱逐进程如何运作
重要的是要理解驱逐过程的工作方式如下:
- 客户端运行新命令,导致添加更多数据。
- Redis检查内存使用情况,如果它大于maxmemory限制,它会根据策略驱逐key。
- 执行新命令,依此类推。
因此,我们不断跨越内存限制的边界,通过检查,然后通过驱逐key返回限制之下。
如果命令导致使用大量内存(如大集合交集然后存储在新key中的)一段时间内,内存限制可以被明显超过。
近似LRU算法
Redis LRU算法不是一个精确的实现。 这意味着Redis无法选择最佳的驱逐候选者,即过去访问次数最多的访问。 相反,它将尝试运行近似的LRU算法,通过采样少量key,并逐出采样key中最好的(具有最早的访问时间)。
然而,自Redis 3.0以来,该算法得到了改进,同时也为一些好的候选人提供了驱逐。 这改善了算法的性能,使其能够更接近地逼近真实LRU算法的行为。
Redis LRU算法的重要之处在于,您可以通过更改样本数来调整算法的精度,以检查每次驱逐。 此参数由以下配置指令控制:
1 |
maxmemory-samples 5 |
Redis之所以不使用真正的LRU实现,是因为它需要更多的内存。 但是,对于使用Redis的应用程序,近似值几乎相同。 以下是Redis使用的LRU近似与真实LRU的比较的图形比较。
生成上述图表的测试填充了具有给定数量键的Redis服务器。 从第一个到最后一个访问key,因此第一个key是使用LRU算法进行驱逐的最佳候选者。 后来增加了50%的key,以迫使一半的旧key被驱逐。
你可以在图中看到三种点,形成三个不同的带。
- 浅灰色带是被驱逐的对象。
- 灰色带是未被驱逐的对象。
- 绿色条带是添加的对象。
在理论上的LRU实现中,我们期望在旧key中,前半部分将过期。 Redis LRU算法将仅在概率上使旧key失效。
正如您所看到的,与Redis 2.8相比,Redis 3.0在5个样本上做得更好,但是最新访问的大多数对象仍然由Redis 2.8保留。 在Redis 3.0中使用10的样本大小,近似值非常接近Redis 3.0的理论性能。
请注意,LRU只是一种模型,用于预测将来访问给定key的可能性。 此外,如果您的数据访问模式与幂律非常相似,那么大多数访问将在LRU近似算法能够很好地处理的key集中。
在模拟中,我们发现使用幂律访问模式,真实LRU和Redis近似之间的差异很小或根本不存在。
但是,您可以以一些额外的CPU使用量为代价将样本大小提高到10,以便接近真实的LRU,并检查这是否会影响您的缓存未命中率。
要使用 CONFIG SET maxmemory-samples <count>
命令对不同的样本量值进行生产实验,非常简单。
新的LFU模式
从Redis 4.0开始,可以使用新的最少使用的逐出模式。 在某些情况下,此模式可能更好(提供更好的命中/未命中率),因为使用LFU Redis将尝试跟踪item的访问频率,以便很少使用的item被驱逐,而使用的item通常具有更高的机会留在内存中。
如果您在LRU中考虑,最近访问但实际上几乎从未请求的item将不会过期,因此风险是驱逐将来有更高机会被请求的key。 LFU没有这个问题,并且通常应该更好地适应不同的访问模式。
要配置LFU模式,可以使用以下策略:
- volatile-lfu在具有过期集的key中使用近似LFU来驱逐。
- allkeys-lfu使用近似的LFU驱逐任何key。
LFU近似于LRU:它使用概率计数器,称为Morris计数器,以便仅使用每个对象的几个位来估计对象访问频率,并结合衰减周期,以便计数器随时间减少:在某些时候我们 不再需要考虑频繁访问的key,即使它们是过去的,因此算法可以适应访问模式的转变。
这些信息的采样与LRU的情况类似(如本文档上一节所述),以便选择驱逐候选者。
然而,与LRU不同,LFU具有某些可调参数:例如,如果频率项不再被访问,它的排名应该有多快? 还可以调整Morris计数器范围,以便更好地使算法适应特定用例。
默认情况下,Redis 4.0配置为:
- 使计数器饱和,大约有一百万个请求。
- 每隔一分钟腐烂柜台。
这些应该是合理的值并且经过实验测试,但是用户可能想要使用这些配置设置以便选择最佳值。
有关如何调整这些参数的说明可以在源代码发布中的示例redis.conf文件中找到,但简单地说,它们是:
1 |
lfu-log-factor 10 |
衰减时间是显而易见的,它是计数器应该被衰减的分钟数,当被采样并且发现比该值更旧时。 特殊值0表示:每次扫描时总是衰减计数器,并且很少有用。
计数器对数因子改变了为了使频率计数器饱和所需的命中数,该频率计数器仅在0-255的范围内。 因子越高,需要越多的访问才能达到最大值。 根据下表,因子越低,低访问计数器的分辨率越高:
1 |
+--------+------------+------------+------------+------------+------------+ |
因此,基本上这个因素是在具有低访问权限和具有高访问权限的区分项目的较好区分项目之间的权衡。 示例redis.conf文件中提供了更多信息自我记录注释。
由于LFU是一项新功能,我们将非常感谢您在使用案例中与LRU相比的任何反馈。
转自:https://jimolonely.github.io/2018/09/03/lang/008-redis-lru-cache/
参考:
https://redis.io/topics/lru-cache
https://raw.githubusercontent.com/antirez/redis/2.8.9/redis.conf
Redis做LRU缓存的更多相关文章
- redis(7)LRU缓存
一.LRU简介 LRU是Least Recently Used的缩写,即:最近最少使用. 它是内存管理中的一种页面置换算法,对于在内存中但是又不用的数据块,操作系统会根据哪些数据属于LRU而将其移除内 ...
- 用redis当作LRU缓存
原文地址:https://redis.io/topics/lru-cache Redis可以用来作缓存,他可以很方便的淘汰(删除)旧数据添加新数据,类似memcached.LRU只是其中的一种置换算法 ...
- Redis学习笔记2-使用 Redis 作为 LRU 缓存
当 Redis 作为缓存使用时,当你添加新的数据时,有时候很方便使 Redis 自动回收老的数据.LRU 实际上是被唯一支持的数据移除方法.Redis 的 maxmemory 指令,用于限制内存使用到 ...
- Redis - 作为 LRU 缓存
一.简介 LRU 实际上是被唯一支持的数据移除方法,同时也是 memcached 默认支持的缓存算法. 二.配置内存大小 在 redis.conf 文件中使用 maxmemory 指令能够配置内存大小 ...
- Spring Boot使用redis做数据缓存
1 添加redis支持 在pom.xml中添加 <dependency> <groupId>org.springframework.boot</groupId> & ...
- Redis作为lru缓存作用
当 Redis 作为缓存使用时,当你添加新的数据时,有时候很方便使 Redis 自动回收老的数据.LRU 实际上是被唯一支持的数据移除方法.Redis 的 maxmemory 指令,用于限制内存使用到 ...
- spring boot:使用caffeine+redis做二级缓存(spring boot 2.3.1)
一,为什么要使用二级缓存? 我们通常会使用caffeine做本地缓存(或者叫做进程内缓存), 它的优点是速度快,操作方便,缺点是不方便管理,不方便扩展 而通常会使用redis作为分布式缓存, 它的优点 ...
- Mybatis的二级缓存、使用Redis做二级缓存
目录 什么是二级缓存? 1. 开启二级缓存 如何使用二级缓存: userCache和flushCache 2. 使用Redis实现二级缓存 如何使用 3. Redis二级缓存源码分析 什么是二级缓存? ...
- 使用redis做mysql缓存
应用Redis实现数据的读写,同时利用队列处理器定时将数据写入mysql. 同时要注意避免冲突,在redis启动时去mysql读取所有表键值存入redis中,往redis写数据时,对redis主键自增 ...
随机推荐
- dos.orm
引言: Dos.ORM(原Hxj.Data)于2009年发布.2015年正式开源,该组件已在数百个成熟项目中应用,是目前国内用户量最大.最活跃.最完善的国产ORM.初期开发过程中参考了NBear与My ...
- Tomcat:3DES解密时中文乱码
情况说明:直接用main方法运行时是没有问题的,web程序一放入tomcat中就会出现解密时乱码. 解决办法: 在解密时,返回string时对数组需要指定UTF-8编码. public static ...
- maven历史版本下载地址
http://archive.apache.org/dist/maven/maven-3/
- JVM·垃圾收集器与内存分配策略之垃圾回收算法!
1.垃圾回收算法 1.1.标记-清除算法(Mark-Sweep): 过程分为“标记”和“清除”两个过程.先将所有需要回收的目标统一标记,然后再统一清除. ...
- HTML5+CSS3点击指定按钮显示某些内容效果
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 金蝶K3 WISE BOM多级展开_销售成本表
/****** Object: StoredProcedure [dbo].[pro_bobang_SaleCost] Script Date: 07/29/2015 16:13:43 ******/ ...
- ELK统一日志系统的应用
收集和分析日志是应用开发中至关重要的一环,互联网大规模.分布式的特性决定了日志的源头越来越分散, 产生的速度越来越快,传统的手段和工具显得日益力不从心.在规模化场景下,grep.awk 无法快速发挥作 ...
- Expression Trees 参数简化查询
ASP.NET MVC 引入了 ModelBinder 技术,让我们可以在 Action 中以强类型参数的形式接收 Request 中的数据,极大的方便了我们的编程,提高了生产力.在查询 Action ...
- 咸鱼入门到放弃7--jsp<二>jsp常用标签
一.JSP标签介绍 JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护. 二.JSP常用标签 ...
- python接口测试-认识POST请求
上午和一个大神交流了一下,给我了一点建议:多做笔记,勤复盘:及时记录自己,最好的提升不是来自于别人,而是来自于自身.我觉得挺有道理的,分享出来.共勉 说正事. 今天把post请求的大概内容看了一下.虽 ...