一、内存淘汰策略重要性

我们都知道redis的性能很高,最主要的原因之一就是redis的数据都在内存中放着,我们在从redis中获取数据或者更新redis中的数据时,都是操作的内存中的数据。而当内存被占满了之后怎么办呢?这时就有必要将一些数据清理掉,以便新的数据能够放到redis中。而清理掉哪些数据?保留哪些数据?什么时候清理?如何配置这些策略?这些就是接下来要研究的内容。

二、Key值过期策略

Redis中可以为key设置过期时间,当到达过期时间后,就需要将这个key删除掉。Redis中提供了两种过期删除策略:惰性删除和定期删除。

定期删除

Redis会将每个设置了过期时间的key放入到一个独立的字典中,以后会定期遍历这个字典来删除到期的key。Redis默认每秒进行10次过期扫描(100ms一次,可以通过修改配置文件redis.conf 的 hz 选项来调整这个次数),但这个扫描并不会扫描过期字典中所有的key,而是通过一种贪心策略来随机筛选删除key,步骤如下:

从过期字典中随机选出20个key;

删除这20个key中已经过期的key;

如果过期的key的比例超过了1/4,那就重复从步骤1开始执行。

之所以采用这种扫描策略,还是为了性能考虑。假如过期字典中有数百万个key,每隔100ms就扫描一次这数百万个key,会给CPU造成很大的负荷,所以,就选择了这种随机筛选部分key,然后按照过期比例来判断是否需要重复执行筛选过期的动作。

正是由于使用了这种扫描策略,定期删除可能会造成很多已经过期的key无法及时删除,所以就有了接下来的惰性删除策略。

惰性删除

所谓惰性删除就是在客户端访问这个key的时候,Redis对key的过期时间进行检查,如果过期了就立即删除,然后返回null。

不管是定期删除还是惰性删除,都是一种不完全精确的删除策略,始终还是会存在已经过期的key无法被删除的场景。而且这两种过期策略都是只针对设置了过期时间的key,不适用于没有设置过期时间的key的淘汰,所以,Redis还提供了内存淘汰策略,用来筛选淘汰指定的key。

三、内存淘汰策略

redis提供的内存淘汰策略中有一部分是基于LRU和LFU实现的,这两种算法实现的,如果对这两种算法不太熟悉,可以先学习下这两种算法

Redis目前共提供了8种内存淘汰策略,其中有两种基于LFU算法的策略是Redis4.0版本之后增加的。接下来让我们一起了解下这8种淘汰策略:

noeviction:只返回错误,不会删除任何key。该策略是Redis的默认淘汰策略,一般不会选用。

volatile-ttl:将设置了过期时间的key中即将过期(剩余存活时间最短)的key删除掉。

volatile-random:在设置了过期时间的key中,随机删除某个key。

allkeys-random:从所有key中随机删除某个key。

volatile-lru:基于LRU算法,从设置了过期时间的key中,删除掉最近最少使用的key。

allkeys-lru:基于LRU算法,从所有key中,删除掉最近最少使用的key。该策略是最常使用的策略。

volatile-lfu:基于LFU算法,从设置了过期时间的key中,删除掉最不经常使用(使用次数最少)的key。

allkeys-lfu:基于LFU算法,从所有key中,删除掉最不经常使用(使用次数最少)的key。

需要注意的是,Redis中的LRU算法并没有严格按照常规的LRU算法的方式实现,而是基于LRU算法的思想做了自己的优化。我们知道,实现LRU算法时,需要将所有的数据按照访问时间距离当前时间的长短排序放到一个双向链表中,基于这个链表实现数据的淘汰。但Redis中存储的数据量是非常庞大的,如果要基于常规的LRU算法,就需要把所有的key全部放到这个双向链表中,这样就会导致这个链表非常非常大,不止需要提供更多的内存来存放这个链表结构,而且操作这么庞大的链表的性能也是比较差的。

所以,Redis中的LRU算法是这样实现的:首先定义一个淘汰池,这个淘汰池是一个数组(大小为16),然后触发淘汰时会根据配置的淘汰策略,先从符合条件的key中随机采样选出5(可在配置文件中配置)个key,然后将这5个key按照空闲时间排序后放到淘汰池中,每次采样之后更新这个淘汰池,让这个淘汰池里保留的总是那些随机采样出的key中空闲时间最长的那部分key。需要删除key时,只需将淘汰池中空闲时间最长的key删掉即可。

为了方便理解它的思想,我画了一个图:

三、Redis内存淘汰策略配置

学习了这8种内存淘汰策略之后,Redis要什么时候会触发执行这些淘汰策略呢?又要怎么指定使用哪一种淘汰策略呢?这就要去Redis的配置文件中进行配置了

配置redis最大内存

在配置文件redis.conf 中,可以通过参数 maxmemory 来设定最大内存:

当数据内存达到 maxmemory 时,便会触发redis的内存淘汰策略。该参数通常设定为其物理内存的四分之三。

配置redis淘汰策略

在配置文件redis.conf 中,通过设置 maxmemory-policy 来指定使用哪种内存淘汰策略:

配置最大采样数量

上文在讲Redis的LRU算法的时候,提到了Redis每次会随机选择5个key放入淘汰池中,这个5的数量就是在redis.conf配置文件中通过 maxmemory-samples 选项配置的:

Redis内存淘汰策略的更多相关文章

  1. Redis数据结构和使用场景,redis内存淘汰策略

    什么样的数据适合放入Redis? sql执行耗时特别久,且结果不频繁变动的数据,适合放入Redis. Redis是单线程的,为什么会这么快? 纯内存操作 单线程操作,避免频繁的上下文切换 采用了非阻塞 ...

  2. LRU工程实现源码(一):Redis 内存淘汰策略

    目录 内存淘汰是什么?什么时候内存淘汰 内存淘汰策略 Redis中的LRU淘汰算法 源码剖析 第一步:什么时候开始淘汰key 配置读取 检查时机 getMaxmemoryState 第二步:淘汰哪些k ...

  3. Redis详解(十一)------ 过期删除策略和内存淘汰策略

    在介绍这篇文章之前,我们先来看如下几个问题: ①.如何设置Redis键的过期时间? ②.设置完一个键的过期时间后,到了这个时间,这个键还能获取到么?假如获取不到那这个键还占据着内存吗? ③.如何设置R ...

  4. 面试官:Redis 过期删除策略和内存淘汰策略有什么区别?

    作者:小林coding 计算机八股文网站:https://xiaolincoding.com 大家好,我是小林. Redis 的「内存淘汰策略」和「过期删除策略」,很多小伙伴容易混淆,这两个机制虽然都 ...

  5. Redis系列11:内存淘汰策略

    Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5: ...

  6. Redis的过期策略和内存淘汰策略(转)

    Redis的过期策略 我们都知道,Redis是key-value数据库,我们可以设置Redis中缓存的key的过期时间.Redis的过期策略就是指当Redis中缓存的key过期了,Redis如何处理. ...

  7. Redis的过期策略和内存淘汰策略

    Redis的过期策略:通常有三种,Redis中同时使用惰性过期和定期过期两种过期策略组合. 定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除.该策略可以立即清除过期的数据 ...

  8. redis键的过期和内存淘汰策略

    键的过期时间 设置过期时间 Redis可以为存储在数据库中的值设置过期时间,作为一个缓存数据库,这个特性是很有帮助的.我们项目中的token或其他登录信息,尤其是短信验证码都是有时间限制的. 按照传统 ...

  9. Redis的内存淘汰策略

    Redis占用内存大小 我们知道Redis是基于内存的key-value数据库,因为系统的内存大小有限,所以我们在使用Redis的时候可以配置Redis能使用的最大的内存大小. 1.通过配置文件配置 ...

  10. Redis系列之-—内存淘汰策略(笔记)

    一.Redis ---获取设置的Redis能使用的最大内存大小 []> config get maxmemory ) "maxmemory" ) " --获取当前内 ...

随机推荐

  1. 第四章:基本Git概念(重点)

    本章通过讨论Git的基本架构组成和一些重要概念,来探讨Git的不同之处和原因. 一: 基本概念 1.版本库. 1]Git版本库只是一个简单的数据库,包含所有用来维护与管理项目的修订版本和历史记录. 2 ...

  2. WDA学习(24):Context Menu使用

    1.17 UI Element:Context Menu使用 本实例测试创建Context Menu. 1.创建Component,View: V_CONTEXT_MENU; 2.创建Context节 ...

  3. web测试:test过程中接口报错 "Object reference not set to an instance of an object."

    "Object reference not set to an instance of an object." 对象引用未设置为对象的实例 可能原因: 1.参数类型传错,或少传参数 ...

  4. 前端入门知识点笔记本之js重定位函数

    1. call().bind().apply()的用法,改变this的指向,区别在于f.call(obj, arg1, arg2...),f.bind(obj, arg1, arg2,...)(),f ...

  5. scala流程控制

    1.分支控制if-else 分支控制有三种:单分支.双分支.多分支: 1.1 单分支 (1).语法入下: if(条件表达式){ 执行代码块       //当条件表达式为true时,才会执行代码块内容 ...

  6. 关于SVN状态图标不显示的解决办法

    一.参考网址 地址:https://blog.csdn.net/qq_33521184/article/details/126562881 二.详情: 第一步: 通过svn的设置来解决 右键-> ...

  7. centos7 硬盘扩容

    参考 linux系统下,新加硬盘并把现有的/home目录扩容 最后加的容量在/目录 而不是在/home目录,而我本来把/home目录独立挂载在一个分区了 创建逻辑卷.可用使用命令 pvcreate / ...

  8. GVINS文章暴力翻译(仅供自学)

    https://blog.csdn.net/haner27/article/details/117929327

  9. homework2软件方法论

    什么是软件工程方法论? 1.软件工程是一个方法论,就是我们在开始一个项目时,大体框架一定要有这么一个概念,而具体实施时,必须根据公司一些特点,优化项目开发的流程,这样才是有实效而方法论只是软件工程的结 ...

  10. C代码调用C++动态库

    最近在工作中遇到了修改C++代码嵌入到C代码中去,C肯定不能直接用C++代码,就需要自己去修改成C代码,所以我就决定在C中调用C++动态库(谁让我懒呢),话不多说,直接上步骤 第一步:编写C++代码 ...