zoukankan      html  css  js  c++  java
  • Redis详解(十一)- 过期删除策略和内存淘汰策略

     


      在介绍这篇文章之前,我们先来看如下几个问题:

      ①、如何设置Redis键的过期时间?

      ②、设置完一个键的过期时间后,到了这个时间,这个键还能获取到么?假如获取不到那这个键还占据着内存吗?

      ③、如何设置Redis的内存大小?当内存满了之后,Redis有哪些内存淘汰策略?我们又该如何选择?

      如果上面的几个问题你都懂,那么下面的内容你就不用看了;如果你不是很懂,那就带着这些问题往下看。

    1、设置Redis键过期时间

      Redis提供了四个命令来设置过期时间(生存时间)。

      ①、EXPIRE <key> <ttl> :表示将键 key 的生存时间设置为 ttl 秒。

      ②、PEXPIRE <key> <ttl> :表示将键 key 的生存时间设置为 ttl 毫秒。

      ③、EXPIREAT <key> <timestamp> :表示将键 key 的生存时间设置为 timestamp 所指定的秒数时间戳。

      ④、PEXPIREAT <key> <timestamp> :表示将键 key 的生存时间设置为 timestamp 所指定的毫秒数时间戳。

      PS:在Redis内部实现中,前面三个设置过期时间的命令最后都会转换成最后一个PEXPIREAT 命令来完成。

      另外补充两个知识点:

      一、移除键的过期时间

      PERSIST <key> :表示将key的过期时间移除。

      二、返回键的剩余生存时间

      TTL <key> :以秒的单位返回键 key 的剩余生存时间。

      PTTL <key> :以毫秒的单位返回键 key 的剩余生存时间。

    2、Redis过期时间的判定

      在Redis内部,每当我们设置一个键的过期时间时,Redis就会将该键带上过期时间存放到一个过期字典中。当我们查询一个键时,Redis便首先检查该键是否存在过期字典中,如果存在,那就获取其过期时间。然后将过期时间和当前系统时间进行比对,比系统时间大,那就没有过期;反之判定该键过期。

    3、过期删除策略

      通常删除某个key,我们有如下三种方式进行处理。

    ①、定时删除

      在设置某个key 的过期时间同时,我们创建一个定时器,让定时器在该过期时间到来时,立即执行对其进行删除的操作。

      优点:定时删除对内存是最友好的,能够保存内存的key一旦过期就能立即从内存中删除。

      缺点:对CPU最不友好,在过期键比较多的时候,删除过期键会占用一部分 CPU 时间,对服务器的响应时间和吞吐量造成影响。

    ②、惰性删除

      设置该key 过期时间后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key。

      优点:对 CPU友好,我们只会在使用该键时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查。

      缺点:对内存不友好,如果一个键已经过期,但是一直没有使用,那么该键就会一直存在内存中,如果数据库中有很多这种使用不到的过期键,这些键便永远不会被删除,内存永远不会释放。从而造成内存泄漏。

    ③、定期删除

      每隔一段时间,我们就对一些key进行检查,删除里面过期的key。

      优点:可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除,也能有效释放过期键占用的内存。

      缺点:难以确定删除操作执行的时长和频率。

         如果执行的太频繁,定期删除策略变得和定时删除策略一样,对CPU不友好。

         如果执行的太少,那又和惰性删除一样了,过期键占用的内存不会及时得到释放。

         另外最重要的是,在获取某个键时,如果某个键的过期时间已经到了,但是还没执行定期删除,那么就会返回这个键的值,这是业务不能忍受的错误。

    4、Redis过期删除策略

      前面讨论了删除过期键的三种策略,发现单一使用某一策略都不能满足实际需求,聪明的你可能想到了,既然单一策略不能满足,那就组合来使用吧。

      没错,Redis的过期删除策略就是:惰性删除和定期删除两种策略配合使用。

      惰性删除:Redis的惰性删除策略由 db.c/expireIfNeeded 函数实现,所有键读写命令执行之前都会调用 expireIfNeeded 函数对其进行检查,如果过期,则删除该键,然后执行键不存在的操作;未过期则不作操作,继续执行原有的命令。

      定期删除:由redis.c/activeExpireCycle 函数实现,函数以一定的频率运行,每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查,并删除其中的过期键。

      注意:并不是一次运行就检查所有的库,所有的键,而是随机检查一定数量的键。

      定期删除函数的运行频率,在Redis2.6版本中,规定每秒运行10次,大概100ms运行一次。在Redis2.8版本后,可以通过修改配置文件redis.conf 的 hz 选项来调整这个次数。

      

      看上面对这个参数的解释,建议不要将这个值设置超过 100,否则会对CPU造成比较大的压力。

      我们看到,通过过期删除策略,对于某些永远使用不到的键,并且多次定期删除也没选定到并删除,那么这些键同样会一直驻留在内存中,又或者在Redis中存入了大量的键,这些操作可能会导致Redis内存不够用,这时候就需要Redis的内存淘汰策略了。

    5、内存淘汰策略

    ①、设置Redis最大内存

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

      

      不设定该参数默认是无限制的,但是通常会设定其为物理内存的四分之三。(这里有个疑惑:为啥作者不考虑将此参数设定为百分比呢?)

    ②、设置内存淘汰方式

      当现有内存大于 maxmemory 时,便会触发redis主动淘汰内存方式,通过设置 maxmemory-policy ,有如下几种淘汰方式:

      1)volatile-lru   利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used ) 。

      2)allkeys-lru   利用LRU算法移除任何key (和上一个相比,删除的key包括设置过期时间和不设置过期时间的)。通常使用该方式

      3)volatile-random 移除设置过过期时间的随机key 。

      4)allkeys-random  无差别的随机移除。

      5)volatile-ttl   移除即将过期的key(minor TTL) 

      6)noeviction 不移除任何key,只是返回一个写错误 ,默认选项,一般不会选用。

      在redis.conf 配置文件中,可以设置淘汰方式:

      

    6、总结

      通过上面的介绍,相信大家对Redis的过期数据删除策略和内存淘汰策略有一定的了解了。这里总结一下:

      Redis过期删除策略是采用惰性删除和定期删除这两种方式组合进行的,惰性删除能够保证过期的数据我们在获取时一定获取不到,而定期删除设置合适的频率,则可以保证无效的数据及时得到释放,而不会一直占用内存数据。

      但是我们说Redis是部署在物理机上的,内存不可能无限扩充的,当内存达到我们设定的界限后,便自动触发Redis内存淘汰策略,而具体的策略方式要根据实际业务情况进行选取。

  • 相关阅读:
    Codeforces 1291 Round #616 (Div. 2) B
    总结
    刷新DNS解析缓存+追踪+域名解析命令
    数学--数论--Hdu 5793 A Boring Question (打表+逆元)
    Lucene.net(4.8.0) 学习问题记录六:Lucene 的索引系统和搜索过程分析
    LeetCode 117 Populating Next Right Pointers in Each Node II
    LeetCode 116 Populating Next Right Pointers in Each Node
    test test
    LeetCode 115 Distinct Subsequences
    LeetCode 114. Flatten Binary Tree to Linked List
  • 原文地址:https://www.cnblogs.com/hiramxq/p/13431376.html
Copyright © 2011-2022 走看看