redis过期策略

    我们使用redis的时候一般会设置过期时间;

    redis设置过期时间:

    expire 只针对顶级key有效,即哈希结构不支持过期(value为hash结构的时候,不能对hash中的某一部分进行过期设置);

    expire key time(以秒为单位)--这是最常用的方式;

    setex(String key, int seconds, String value)--字符串独有的方式  ;

    拓展:

    1. 除了字符串自己独有设置过期时间的方法外,其他方法都需要依靠expire方法来设置时间

    2. 如果没有设置过期时间,那缓存就是永不过期

    3. 如果设置了过期时间,之后又想让缓存永不过期,使用persist key

 

    当设置了过期时间,redis是如何判断是否过期,以及根据什么策略来进行删除的?redis一般通过三种策略来实现过期删除;

删除策略总结:

(1)定时删除:在设置key的过期时间的同时,为该key创建一个定时器,在时间到了时候,服务器立刻对键进行删除;

  • 过期键能尽可能被删除,并释放内存(内存可以被尽快释放);
  • 在过期键比较多的情况下,删除操作可能会占用一部分CPU时间。当内存不紧张而CPU非常紧张的情况下,会对服务器响应时间和吞吐量造成影响;
  • 定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重;

       注:当大量请求等待服务器处理时,服务器应该优先处理请求而不是删除过期键。另外,创建定时器需要用到时间事件(由无序链表实现),以至于查找一个事件的时间复杂度为O(N),并不能高效的处理大量时间事件;

(2)惰性删除:每次从键空间获取键时(每次通过key获取值的时候),都检查是否过期,过期则删除并返回null,未过期,则返回该键;

  • 只有取出键时才对其进行过期检查,不会删除其他键,不会花费CPU太多时间。若一个键早已过期,但一直未被取到,它便会一直占用内存。若有大量的未被访问的键,而服务器又不会主动释放,就会造成大量的内存浪费。

(3)定期删除:每隔一段时间删除里面的过期键;

  • 每隔一段时间删除过期键,减少了对cpu占用时间的影响;
  • 也有效的减少了过期键过多而造成的内存浪费;
  • 删除操作执行的时长和频率。既不能太频繁也不能太稀疏,需合理设置;

 

注释:memcached只是用了惰性删除,而redis同时使用了惰性删除与定期删除,这也是二者的一个不同点(可以视为redis优于memcached的一点);

对于惰性删除而言,并不是只有获取key的时候才会检查key是否过期,在某些设置key的方法上也会检查

(eg.setnx key2 value2:该方法类似于memcached的add方法,如果设置的key2已经存在,那么该方法返回false,什么都不做;如果设置的key2不存在,那么该方法设置缓存key2-value2。假设调用此方法的时候,发现redis中已经存在了key2,但是该key2已经过期了,如果此时不执行删除操作的话,setnx方法将会直接返回false,也就是说此时并没有重新设置key2-value2成功,所以对于一定要在setnx执行之前,对key2进行过期检查)。

 

Redis采用的过期策略:

       惰性删除+定期删除

       惰性删除流程:

  • 在进行get或setnx等操作时,先检查key是否过期;
  • 若过期,删除key,然后执行相应操作;
  •  若没过期,直接执行相应操作;

        定期删除流程(简单而言,对指定个数个库的每一个库随机删除小于等于指定个数个过期key):

  • 遍历每个数据库(就是redis.conf中配置的"database"数量,默认为16)
  • 检查当前库中的指定个数个key(默认是每个库检查20个key,注意相当于该循环执行20次,循环体是下边的描述)
  • 如果当前库中没有一个key设置了过期时间,直接执行下一个库的遍历
  • 随机获取一个设置了过期时间的key,检查该key是否过期,如果过期,删除key
  • 判断定期删除操作是否已经达到指定时长,若已经达到,直接退出定期删除。

 

    对于定期删除,在程序中有一个全局变量current_db来记录下一个将要遍历的库,假设有16个库,我们这一次定期删除遍历了10个,那此时的current_db就是11,下一次定期删除就从第11个库开始遍历,假设current_db等于15了,那么之后遍历就再从0号库开始(此时current_db==0)

 

    在实际中,如果我们要自己设计过期策略,在使用惰性删除+定期删除时,控制时长和频率这个尤为关键,需要结合服务器性能,已经过并发量等情况进行调整,以致最佳。

 

redis中的过期键设置命令:

  • SETEX命令:在设置一个字符串的同时为键设置过期时间,只针对数据类型为String的K-V。
  • TTL和PTTL命令:接受一个带生存时间或者过期时间的键,返回这个键的剩余时间。
  • EXPIRE :将key生存时间设置为ttl秒。
  • PEXPIRE:将key生存时间设置为ttl毫秒。
  • EXPIREAT :将键key的过期时间设置为timestamp所指定的秒数时间戳;
  • PEXPIREAT: 将键key的过期时间设置为timestamp所指定的豪秒数时间戳;

redis定期删除策略详述:

    过期键的定期删除策略由redis.c/activeExpireCycle函数实现 ;

  • 函数每次运行时,都从一定数量的数据库(redis)中取出一定数量的随机键检查,并删除过期键;
  • 全局变量current_db会记录当前函数的检查进度,在下一次调用时,接着上次的进度处理。如果当前函数遍历10号(redis)数据库返回了,下次就会从11号开始;
  • 随着函数的执行,所有数据库都被检查一遍后,全局变量current_db会置为0,然后重新开始;

复制功能下如何处理:

    主从复制模式下,过期键的删除由主服务器控制;

  • 主服务删除一个过期键后,会显示的向从服务器发送DEL命令,告知删除该键;
  • 从服务器只有接收到主服务器发送来的DEL命令,才会删除过期键。否则不会删除,并且像正常键一样处理;保持数据的一致性;

RDB和AOF时如何处理过期键:

RDB 

  • 以主服务器模式运行,在载入RDB文件时,未过期的键才会被载入,过期键被忽略;
  • 以从服务器模式运行,所有键都将载入;

AOF写入

  • 若某键已过期,程序会向AOF文件追加一条DEL,来显示删除;

AOF重写

  • 已过期的键不会保存到重写的AOF文件中;

 

 

 

 

你可能感兴趣的:(redis,过期设置,过期策略,redis)