Redis(七):Redis内存淘汰

Redis 使用主动和被动淘汰策略管理内存。主动淘汰通过键的生存周期,如定时删除、惰性删除和定期删除来清理过期键。被动淘汰在内存超过限制时,依据不同策略(如LRU、TTL等)选择键进行淘汰。内存淘汰过程涉及expireIfNeeded和freeMemoryIfNeeded函数,以及缓冲池策略以优化淘汰效率。
摘要由CSDN通过智能技术生成

1. 主动淘汰

    1.1 键的生存周期

    1.2 过期键删除策略

2. 被动淘汰

    2.1 被动淘汰策略

    2.2 被动淘汰策略的实现


    由于redis是一个内存数据库,所有键值对都保存在内存中,而内存的数量毕竟不是无限的,因此当redis中保存的键值对超过一定数量时,就需要淘汰掉一些键值对,减少redis所占的内存空间。redis有两种内存淘汰策略,一种称为主动淘汰,一种称为被动淘汰。主动淘汰即为redis的键值对设置过期时间,当时间到期之后,对应的键值对就会从内存中删除。而被动淘汰则是给redis的内存设置一个最大的限制,当内存使用超过这个限制时,就会采用一定的策略算法被动的删掉一部分键值对,接下来我们分别进行介绍。

1. 主动淘汰

1.1 键的生存周期

     通过EXPIRE命令,客户端可以以秒或者毫秒的精度为数据库的某个键设置生存周期,经过指定的秒或者毫秒之后,服务器就会自动删除生存周期为0的键。redisDb结构的expires字典保存了数据库中所有键的过期时间,我们称这个字典为过期字典。

typedef struct redisDb {
 
    
    // 过期字典,保存者键的过期时间
    dict *expires;
 
} redisDb;

    redis过期键的删除策略主要有三种,分别是:

  • 定时删除:设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。定时删除对CPU不友好。
  • 惰性删除:放任过期键不管,但是每次从键空间获取键时,都检查键是否过期,过期则删除,否则则返回。惰性删除对内存不友好。
  • 定期删除:每隔一段时间,程序对数据库进行一次检查,删除里面的过期键。至于删除多少过期键,检查多少数据库,由算法决定。定期删除是定时删除和惰性删除的折中。

1.2 过期键删除策略

    redis 服务器实际上采用了惰性删除和定期删除两种策略相结合的方式:

(1)惰性删除的实现:

    惰性删除由expireIfNeeded函数实现,所有读写数据库的redis命令在执行前都会调用这个函数对输入的键进行检查,如果输出的键已经过期,则将键从数据库中删除。    

(2)定期删除的实现:

    定期删除由activeExpireCycle函数实现,它在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expires字段中随机检查一部分过期时间,并删除其中的过期键。该函数的有两种,分别是快速模式(ACTIVE_EXPIRE_CYCLE_FAST)和正常模式(ACTIVE_EXPIRE_CYCLE_SLOW):

  • 在快速模式下,执行的时间不会长过 1000(EXPIRE_FAST_CYCLE_DURATION )微秒,并且在 1000(EXPIRE_FAST_CYCLE_DURATION )微秒之内不会再重新执行。快速模式会在事件循环每次循环的beforeSleep函数中调用。
  • 在正常模式下,执行的时间不会超过CPU时间的25%,即100ms * 25%,为25ms,这里的100ms表示serverCron函数1s调用10次。正常模式会在时间事件的serverCron函数中调用。    

2. 被动淘汰

2.1 被动淘汰策略

    Redis的所占用的最大内存可以在配置文件的maxmemory中设置,而Redis的内存淘汰策略则可以通过maxmemory-policy和maxmemory-samples来设置。当redis所占的内存大于配置文件所设置的内存时,redis需要从所有键中选择一个键进行淘汰。Redis有6种内存淘汰策略,分别是:

/* Redis maxmemory strategies */
#define REDIS_MAXMEMORY_VOLATILE_LRU 0

#define REDIS_MAXMEMORY_VOLATILE_TTL 1

#define REDIS_MAXMEMORY_VOLATILE_RANDOM 2

#define REDIS_MAXMEMORY_ALLKEYS_LRU 3

#define REDIS_MAXMEMORY_ALLKEYS_RANDOM 4

#define REDIS_MAXMEMORY_NO_EVICTION 5

#define REDIS_DEFAULT_MAXMEMORY_POLICY REDIS_MAXMEMORY_NO_EVICTION
  • volatile-lru: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key,对应宏定义REDIS_MAXMEMORY_VOLATILE_LRU
  • volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。对应宏定义REDIS_MAXMEMORY_VOLATILE_TTL
  • volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。对应宏定义REDIS_MAXMEMORY_VOLATILE_RANDOM
  • allkeys-lru: 所有key通用,优先删除最近最少使用(less recently used ,LRU) 的 key。对应宏定义REDIS_MAXMEMORY_ALLKEYS_LRU
  • allkeys-random: 所有key通用; 随机删除一部分 key。对应宏定义REDIS_MAXMEMORY_ALLKEYS_RANDOM
  • noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息,这是默认的淘汰策略。对应宏定义REDIS_MAXMEMORY_NO_EVICTION

    注意:对于LRU淘汰策略,redis中并不会准确的删除所有键中最近最少使用的键,而是随机抽取maxmeory-samples个键,删除这些键中空转时间最大的键。此外,Redis还使用了一个缓冲池来保存历次淘汰时那些空转时长最大的键,进行新一轮淘汰时,会将这随机选择的maxmeory-samples个键和缓冲池中的键进行比较,然后选出空转时长最大的那个。采用缓冲池策略,把一个全局排序问题转化成为了局部的比较问题。缓冲池大小由宏REDIS_EVICTION_POOL_SIZE定义,大小为16。

2.2 被动淘汰策略的实现

    主要由freeMemoryIfNeeded函数实现内存淘汰,每次执行客户端的命令时都会调用这个函数,该函数的整个计算流程如下图所示。

   

(1)计算Redis目前所占的内存总数时,有两个方面的内存不会计算在内,分别是:

  • 所有从服务器slave的输出缓冲区的内存
  • AOF 缓冲区的内存server.aof_buf和AOF重写缓冲区的缓存

(2)循环中每次删除时,只选择一个键进行删除,删除流程为:

  • 如果策略是 allkeys-lru 或者 allkeys-random,那么淘汰的目标为所有数据库键;如果策略是 volatile-lru 、 volatile-random 或者 volatile-ttl,那么淘汰的目标为带过期时间的数据库键;

  • 如果使用的是随机策略(volatile-random、allkeys-random policy),那么从目标字典中随机选出键;

  • 如果使用的是 LRU 策略(volatile-lru、allkeys-lru policy),那么从一集 sample 键中选出 IDLE 时间最长的那个键,IDEL时间为当前时间减去每个键所保存的lru时间

  • 如果策略为TTI(volatile-ttl) ,从一集 sample 键中选出过期时间距离当前时间最接近的键;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值