Redis过期策略和内存淘汰策略

过期策略

缓存,不是存储,无法保证以前设置的缓存绝对存在。因为缓存容量是有上限的,即使set值的时候不设置过期时间,在内存不够的时候,会根据内存淘汰策略删除一些缓存。设置过期时间的key是如何删除的?过期后会立即释放内存吗?

定时删除

创建一个定时器,对key设置有效时间,且过期时间达到时,由定时器任务立即执行对键的删除操作。
优点:节约内存到点就删除,快速释放掉不必要的内存占用。
缺点:cpu压力很大,无论cpu此时负载量多高,均占用cpu,会影响redis服务器响应时间和指令吞吐量。

例如:正有大量的命令请求在等待服务器处理,并且服务器当前不缺少内存的情况下,服务器应当优先将CPU时间用在处理客户端的命令请求上面,而不是用在删除过期key上面。

用处理器的性能换存储空间,牺牲cpu处理时长来保障内存可以最大化的释放(时间换空间)

惰性删除

数据到达过期时间后,不做处理,等下次访问该数据的时候回进行一个判断,如果发现数据以及过期,删除数据并返回不存在,如果发现数据没有过期,就返回该key的值。

此策略对CPU时间来说是最友好的,只在取出key时,才对key进行过期检查,即只会在非做不可的情况下进行,并且删除的目标仅限于当前处理的key,不会在删除其他无关的过期key上花费任何CPU时间。

此策略的缺点是对内存是最不友好的。如果一个key已经过期,而这个key又仍然保留在db中,那么只要这个过期key不被删除,它所占用的内存就不会释放。

例如,如果db中有非常多的过期key,而这些过期key又恰好没有被访问到的话,那它们也许永远也不会被删除

典型的用存储空间换取处理器性能 (用空间换时间)

定期删除

定期删除是每隔一段时间,程序就会对Redis数据进行一次检查,删除里面的过期key,至于要删除多少过期key,以及要检查多少个db,则是由Redis内部算法决定

Redis会根据设置的参数,定期对具有时效性的key进行清理工作,它是定时删除和惰性删除的结合者,既不像定时删除会立即进行删除给予CPU压力,也不会像惰性删除给予内存压力

Redis启动服务器初始化时,读取配置server.hz的值,默认为10
每秒钟执行server.hzserverCron()对服务器进行一个定时轮询,轮询中继续对每一个库进行databasesCron()访问在访问的过程中

结构图
结构图

在里面执行activeExpireCycle()操作,对每个expires[*](存储的过期数据数据地址和过期时间,有多少个DB就有多少个expires,Redis默认16个)逐一进行检测,每次执行250ms/server.hz
对某个expires[*]每一个key进行检测,检测时随机挑选个key检测
如果key超时,删除key
如果一轮中删除的key的数量>W*25%(比如100个删除70个),循环该过程继续执行对剩下的key进行检测
如果一轮中删除的key的数量≤W25%,检查下一个expires[],0-15循环(redis一共16个数据库)

W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 属性值(周期查找的循环次数,每次循环要找多少个)

expires[*]执行完了下次来又从几开始执行嫩?
参数current_db用于记录当前检测activeExpireCycle() 进入哪个expires[*] 执行
如果activeExpireCycle()执行时间到期,下次从current_db继续向下执行

逐出算法

新数据进入检测,当新数据进入redis时,如果内存不足怎么办?
Redis使用内存存储数据,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。如果内存不满足新加入数据的最低存储要求,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法

注意:逐出数据的过程不是100%能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所 有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息。(error) OOM command not allowed when used memory >'maxmemory'

内存淘汰相关配置

  • 最大可使用内存:maxmemory
    占用物理内存的比例,默认值为0,标识不限制,生产环境中根据需求设定,通常设置50%以上
  • 每次选取待删除数据个数:maxmemory-samples
    选取数据时并不会扫描,导致严重的性能消耗,降低读写性能,因此采用随机获取数据的方式作为待检测删除数据
  • 删除策略:maxmemory-policy
    到达最大内存后的,对被挑选出来的数据进行删除的策略

内存淘汰策略

  • 检测易丢失数据(可能会过期的数据集server.db[i].expires )

    • volatile-lru:挑选最近最近使用时间最少的数据淘汰
    • volatile-lfu:挑选最近使用次数最少的数据淘汰
    • volatile-ttl:挑选将快要过期的数据进行淘汰
    • volatile-random:随机任意选择数据进行淘汰
  • 检测全库数据(所有数据集server.db[i].dict )

    • allkeys-lru:挑选最近最少使用的数据淘汰(在一段时间中最长时间不使用)
    • allkeys-lfu:挑选最近使用次数最少的数据淘汰(在一段时间中使用次数最少的)
    • allkeys-random:任意选择数据淘汰
  • 放弃数据驱逐

    • no-enviction(驱逐):禁止驱逐数据(redis4.0中默认策略),会引发错误OOM(Out Of Memory)

添加新评论

评论列表