键的过期时间
1.0.0版本后可用
时间复杂度:O(1)
给一个key
设置超时时间。在一个超时时间结束后,这个键将会被自动删除。一个拥有关联过期时间的键在Redis术语里通常被认为不稳定的。
只有删除或者覆盖键的内容的命令,包括DEL, SET, GETSET和所有的*STORE
命令,才会把过期时间清除。这意味着从理论上讲,所有改变键上存储的值而不是使用新的值来替换的操作,都将会保持过期时间不变。例如,使用INCR增加一个键的值,使用LPUSH讲一个新的值放到列表中,或者使用HSET改变一个哈希的字段的值都将会使过期时间保持不变。
使用PERSIST命令将一个键变成持久化的键,过期时间也会被清除。
如果一个键被RENAME重命名,关联的生存时间将会被转移到新的键名上。
如果一个键被RENAME重命名,就像在一个已经存在的键Key_A
,它被一个调用RENAME Key_B Key_A
所覆盖,原始的Key_A
是否关联过期时间是没关系的,新的键Key_A
将会继承Key_B
的所有特征。
注意,使用负数调用EXPIRE/PEXPIRE,或者使用过去的时间调用EXPIREAT/PEXPIREAT将会使键被删除,而不是过期(相应的,弹出的key event将会是del
,而不是expired
)。
刷新过期时间
可以使用一个已经有过期时间集的键作为参数来调用EXPIRE。在这种情况下,一个键的生存时间已经更新为一个新值。对此很多应用,下面的Navigation session模式一节记录了一个例子。
与Redis2.1.3之前版本的不同
在Redis 2.1.3之前的版本中,使用一个命令改变一个拥有过期时间的键的值,效果跟彻底移除这个键一样。这种语义是必须的,因为复制层的限制现在已经确定了。
EXPIRE将会返回0,并且不会使用一个过期时间集合来改变一个键的过期时间。
Return value 返回值
特别的返回数字:
-
1
if the timeout was set. -
1
,如果设置了过期时间。 -
0
ifkey
does not exist. -
0
如果一个key
不存在。
例子
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis> SET mykey "Hello World"
"OK"
redis> TTL mykey
(integer) -1
redis>
模式:导航会话
想象你有一个网页服务,并且你对用户最近访问的N个页面有兴趣,这样每个临近的页面视图的执行时间不会超过前一个页面视图执行的60秒。理论上来讲,你可以认为用户访问的页面集合为Navigation session,其中就可以包含用户在寻找哪些他或她感兴趣的产品信息,因此你可以推荐关联的产品。
你可以非常容易的使用下面的策略在Redis中建模这种类型:每次用户访问一个页面你就调用下面的命令:
MULTI
RPUSH pagewviews.user:<userid> http://.....
EXPIRE pagewviews.user:<userid> 60
EXEC
如果用户闲置超过60秒,这个键将会被删除,只有访问时间差值小于60秒的页面才会被记录。
这个模式可以很容易的修改为使用INCR做计数器来替代使用RPUSH的列表。
附录:Redis过期时间
过期的键
通常情况下创建Redis的键时不关联生存时间。这个键将会简单的一直生存,除非用户显示的删除它,例如使用DEL命令。
EXPIRE家族命令能够把一个过期时间关联到一个给定的键,代价是这个键会使用额外的内存。当一个键设置了过期时间,Redis将会确保当指定的时间过去之后移除这个键。
一个键的生存时间可以被EXPIRE命令更新,或者被PERSIST命令完全移除(或其他严格相关的命令)。
过期的精确度
在Redis2.4版本中,过期时间可能不是非常精确的,并且它可能是在0到1秒之间的出入。从Redis2.6版本开始,过期时间误差是从0到1毫秒。
过期与持久化
键的过期信息以绝对的Unix时间戳形式保存(Redis2.6以及更新的版本毫秒内)。这意味着甚至当Redis实例未启动时时间就流走了。
为了过期时间能工作的很好,计算机时间必须保持稳定。如果你从两个时钟巨大不同步的计算机上移动一个RDB文件,有趣的事情将会发生(像所有的键在加载时变成过期)。
实际上运行中的实例将一直会检查计算机的时钟,举例来说,如果你给一个键设置1000秒的生存时间,然后在未来将你的计算机设置在2000秒以后,这个键将会立即失效,而不是持续1000秒。
Redis如何过期键
Redis键将会通过两种方式过期:一个被动的方式,和一个主动的方式。
一个键的被动过期是很简单的,当一些客户端尝试访问它,然后这个键被发现超时了。
当然,这是不够的,因为有一些键将永远不会被再次访问。这些键无论如何都应该被过期。所以,Redis会定期的在过期的集合中随机范围内测试少量的键。所有的已过期的键将会被从键空间被删除。
这就是Redis会在每秒做10次的事情:
- 随机测试20个在集合中关联过期时间的键。
- 删除发现的所有已过期的键。
- 如果超过20%的键已过期,从第一步再次开始。
这是一个小概率的算法,基本的设想是我们的样本代表整个键空间,然后我们继续失效直到将要失效的键百分比小于25%。
这意味着在任何一个时刻,正在使用内存的已经过期的最大数量的键等于每秒最大写操作数量除以4.
在副本链接和AOF文件中如何处理过期
为了获得正确的行为而不牺牲一致性,当一个键失效,DEL操作会同时在AOF文件和附属的副节点执行。这种方式失效进程是在主实例集中的,也不会出现一致性错误。
然而,当副本已经连接到主节点后将不会独立的失效键(但将会等待来自主节点的DEL),他们仍将会获取数据集中的全部过期状态,所以当一个副本被选举为主节点后,它将能够独立的失效这些键,完全像一个主节点。