首页 > 编程知识 正文

redis内存回收机制,redis存储

时间:2023-05-04 09:30:09 阅读:133180 作者:4245

过期密钥删除策略知道数据库密钥的过期时间存储在过期词典中,以及如何根据过期时间确定密钥是否过期,如上一节所述。 现在剩下的问题是,密钥过期的话,什么时候会被删除?

这个问题有三个可能的答案,每个答案代表三个不同的删除策略。

定时器删除:在设定关键帧过期时间的同时,创建“定时器”(timer ),以便定时器在关键帧过期时间临时执行关键帧删除操作。 惯性删除:保留密钥的有效期限,但每次从密钥空间获取密钥时,都会检查获取的密钥是否超过有效期限,过期时删除该密钥; 如果未过期,则返回密钥。 定期删除:程序每隔一段时间检查数据库并删除过期的密钥。 算法决定要删除的过期密钥的数量以及要检查的数据库数量。 一方面,日程删除的日程删除策略对内存最友好。 通过使用计时器,计划删除策略将尽快删除过期密钥,并释放过期密钥使用的内存。

另一方面,计划删除策略的缺点是对CPU时间最不友好。 在到期密钥较多的情况下,删除到期密钥的行为可能会消耗相当大的CPU时间,内存并不紧张,但在CPU时间非常紧张的情况下,如果将CPU时间用于删除与当前任务无关的到期密钥,则会影响服务器的响应时间和吞吐量

例如,如果有大量命令请求正在等待服务器处理,且服务器当前没有足够的内存,则服务器应该优先使用CPU时间来处理客户端的命令请求,而不是删除过期密钥。 此外,虽然要创建计时器,必须在Redis服务器上使用时间事件,但当前时间事件的实现方式-无序链表、查找事件的时间复杂性为o(n ) -无法有效处理大量时间事件

因此,让服务器创建大量的计时器来实现定时删除策略在现阶段是不现实的。

二、惯性清除策略对CPU时间最友好。 程序只在取出密钥时进行密钥的有效期限检查。 这样,可以保证只有在不能进行删除过期键的操作的情况下才进行。 另外,删除的对象不限于当前处理的键。 此策略不花费CPU时间删除其他无关的过期密钥。

惯性删除策略的缺点是对内存最不友好。 如果密钥过期,但该密钥仍保留在数据库中,则除非删除该过期密钥,否则不会释放正在使用的内存。

如果使用惯性删除策略,则数据库中有非常多的过期密钥,并且这些过期密钥未被访问,则除非用户手动运行FLUSHDB,否则它们可能不会被删除。 这也可以被认为是内存泄漏。 不需要的垃圾数据占用大量内存,服务器不会自行释放。 对于运行状态非常依赖内存的Redis服务器来说,情况确实并非如此

例如,对于与时间相关的数据(如日志(log ) ),从某个时间点开始,访问将大幅减少或不再访问。 如果数据库中大量存储了这些过期的数据,则用户认为服务器自动删除了这些密钥,但实际上这些密钥仍然存在,密钥占用的内存也没有释放,这无疑会导致严重的后果。

三、定期删除面临定时删除和惯性删除的争论,这两种删除方式在单一使用时存在明显缺陷。

删除计划需要太长的CPU时间,这会影响服务器的响应时间和吞吐量。 惰性删除太浪费内存,有内存泄漏的危险。 定期删除策略是前两个策略的集成和折中。

定期删除策略每隔一段时间执行删除过期密钥操作,并限制删除操作的执行时间和频率,从而减少删除操作对CPU时间的影响。 此外,通过定期删除过期密钥,定期删除策略有效地减少了过期密钥占用的内存。 定期删除策略的难点是确定删除操作的执行时间和频率。

如果删除操作频繁或运行时间过长,则定期删除策略会缩减为计划的删除策略,而CPU时间太多用于删除过期密钥。 如果执行删除操作太少或执行时间太短,则定期删除策略可能会像惰性删除包一样浪费内存。 因此,采用定期删除策略后,服务器必须根据情况适当设置删除操作的执行时间和执行频率。

默认情况下,redis每100ms检查一次,删除是否有过期的密钥,如果有过期的密钥。 另外,redis不是每100ms检查一次所有key,而是随机抽取进行检查(如果每100ms检查所有key,redis会不会堵塞)。 因此,如果只采用定期删除策略,许多密钥将不会在时间之前删除。

Redis服务器实际上使用了两种策略:惯性删除和定期删除。 这两种删除策略的结合使服务器能够合理使用CPU时间,并在不浪费内存空间的情况下实现平衡。

——上自dst着《Redis设计与实现》107页

过期策略存在的问题

无法扫描和删除所有过期的密钥,因为redis的定期删除是随机提取检查。 此后,由于没有请求某些密钥,因此也不会触发惯性删除。 这将增加redis的内存使用量。 在这种情况下,需要内存销毁机制。

内存销毁机制的最大内存设置是通过设置最大内存完成的。 以maxmemory bytes的形式,当当前使用的内存超过设置的最大内存时,将释放内存。 如果需要释放内存,则必须通过某种策略删除存储的对象。 Redis有六个策略。 默认策略为volatile-lru。

瑞迪命中

内存超过限制时,按照配置的策略,淘汰掉相应的key-value,使得内存可以继续留有足够的空间保存新的数据。redis 确定驱逐某个键值对后,会删除这个数据并,并将这个数据变更消息发布到本地(AOF 持久化)和从机(主从连接)。

volatile-lru:使用LRU算法进行数据淘汰(淘汰上次使用时间最早的,且使用次数最少的key),只淘汰设定了有效期的key ;allkeys-lru:使用LRU算法进行数据淘汰,所有的key都可以被淘汰;volatile-random:随机淘汰数据,只淘汰设定了有效期的key;allkeys-random:随机淘汰数据,所有的key都可以被淘汰;volatile-ttl:淘汰剩余有效期最短的key;no-enviction:不删除任意数据(但redis还会根据引用计数器进行释放),这时如果内存不够时,会直接返回错误 。

默认的内存策略是noeviction,在Redis中LRU算法是一个近似算法,默认情况下,Redis随机挑选5个键,并且从中选取一个最近最久未使用的key进行淘汰,在配置文件中可以通过maxmemory-samples的值来设置redis需要检查key的个数,但是栓查的越多,耗费的时间也就越久,但是结构越精确(也就是Redis从内存中淘汰的对象未使用的时间也就越久~),设置多少,综合权衡。

其缓存管理功能,由redis.c文件中的freeMemoryIfNeeded函数实现。如果maxmemory被设置,则在每次进行命令执行之前,该函数均被调用,用以判断是否有足够内存可用,释放内存或返回错误。如果没有找到足够多的内存,程序主逻辑将会阻止设置了REDIS_COM_DENYOOM flag的命令执行,对其返回command not allowed when used memory > ‘maxmemory’的错误消息。

一、LRU数据淘汰机制

在服务器配置中保存了 lru 计数器 server.lrulock,会定时(redis 定时程序 serverCorn())更新,server.lrulock 的值是根据 server.unixtime 计算出来的。

另外,从 struct redisObject 中可以发现,每一个 redis 对象都会设置相应的 lru。可以想象的是,每一次访问数据的时候,会更新 redisObject.lru。

LRU 数据淘汰机制是这样的:

在数据集中随机挑选几个键值对,取出其中 lru 最小的键值对淘汰。所以,你会发现,redis并不是保证取得所有数据集中最近最少使用(LRU)的键值对,而只是随机挑选的几个键值对中的。

二、TTL数据淘汰机制

redis 数据集数据结构中保存了键值对过期时间的表,即 redisDb.expires。和 LRU 数据淘汰机制类似。

TTL 数据淘汰机制是这样的:

从过期时间的表中随机挑选几个键值对,取出其中 ttl 最大的键值对淘汰。同样你会发现,redis并不是保证取得所有过期时间的表中最快过期的键值对,而只是随机挑选的几个键值对中的。

过期键删除策略和内存淘汰机制之间的关系:

过期健删除策略强调的是对过期健的操作,如果有健过期了,而内存还足够,不会使用内存淘汰机制,这时也会使用过期健删除策略删除过期健。内存淘汰机制强调的是对内存的操作,如果内存不够了,即使有的健没有过期,也要删除一部分,同时也针对没有设置过期时间的健。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。