key的过期时间
?
使用EXPIRE命令可以为key设置一个过期时间(timeout),过期之后,这个key会被自动删除。在Redis中,一个关联了timeout的key通常被称为易变的。
?
当key被删除或者key的内容被覆盖之后,timeout会被清除。像DEL, SET, GETSET这些命令还有存储相关的命令都会清除timeout。
?
127.0.0.1:6379> set testkey 1
OK
127.0.0.1:6379> expire testkey 120
(integer) 1
127.0.0.1:6379> set testkey 2 # 设置testkey的值为2
OK
127.0.0.1:6379> ttl testkey # timeout被清除了
(integer) -1
127.0.0.1:6379>
?
?
使用PERSIST命令也会清除key的timeout,该命令会删除key上已存在的timeout,使这个key从可变(易变的)的变成持久(persistent)的。
?
127.0.0.1:6379> set testkey 123
OK
127.0.0.1:6379> expire testkey 123
(integer) 1
127.0.0.1:6379> ttl testkey
(integer) 113
127.0.0.1:6379> PERSIST testkey
(integer) 1
127.0.0.1:6379> ttl testkey
(integer) -1
127.0.0.1:6379>
?
下面这些操作不会清除key的timeout,即所有在概念上改变存储在key中的值而不用新值替换它的操作将保持timeout不变。
?
用INCR命令去递增一个key的值
127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> EXPIRE a 60
(integer) 1
127.0.0.1:6379> ttl a
(integer) 58
127.0.0.1:6379> INCR a
(integer) 2
127.0.0.1:6379> ttl a
(integer) 52
127.0.0.1:6379>
?
LPUSH命令向list中追加一个新的值,或者LPOP命令从list中pop一个值
127.0.0.1:6379> LPUSH numbers 0
(integer) 1
127.0.0.1:6379> EXPIRE numbers 60
(integer) 1
127.0.0.1:6379> ttl numbers
(integer) 58
127.0.0.1:6379> LPUSH numbers 1
(integer) 2
127.0.0.1:6379> ttl numbers
(integer) 49
127.0.0.1:6379> LPUSH numbers 2
(integer) 3
127.0.0.1:6379> ttl numbers
(integer) 45
127.0.0.1:6379>
127.0.0.1:6379> LPOP numbers
"2"
127.0.0.1:6379> ttl numbers
(integer) 22
127.0.0.1:6379>
?
HSET命令向SET中添加新的值
127.0.0.1:6379> HSET typeNames 0 零
(integer) 1
127.0.0.1:6379> HSET typeNames 1 一
(integer) 1
127.0.0.1:6379> HSET typeNames 2 二
(integer) 1
127.0.0.1:6379> hget typenames 1
(nil)
127.0.0.1:6379> hget typeNames 1
"\xe4\xb8\x80\x9b\xb6"
127.0.0.1:6379> expire typeNames 60
(integer) 1
127.0.0.1:6379> ttl typeNames
(integer) 56
127.0.0.1:6379> hset typeNames 3 三
(integer) 1
127.0.0.1:6379> ttl typeNames
(integer) 45
127.0.0.1:6379>
?
当使用RENAME对key重命名时,关联到key的timeout会被转移到新的key上。如果新的key已经存在(即覆盖),则新的key的timeout会从key上继承过来。如:将key_a改名为key_b,如果key_b已经存在并且有一个timeout=30,重命名后key_b的timeout会等于key_a的timeout(60)。
?
127.0.0.1:6379> set key_a a # 设置key_a
OK
127.0.0.1:6379> set key_b b # 设置key_b
OK
127.0.0.1:6379> expire key_a 60 # 设置key_a在60s后过期
(integer) 1
127.0.0.1:6379> expire key_b 30 # 设置key_b在30秒后过期
(integer) 1
127.0.0.1:6379> rename key_a key_b # 将key_a重命名为key_b
OK
127.0.0.1:6379> ttl key_a
(integer) -2
127.0.0.1:6379> ttl key_b # key_b继承了key_a的过期时间
(integer) 47
127.0.0.1:6379> get key_b
"a"
127.0.0.1:6379>
?
当给一个key设置的过期时间为负数时会将这个key删除,而不是将这个key设置为已过期。
?
127.0.0.1:6379> set key_a 60
OK
127.0.0.1:6379> EXPIRE key_a -3
(integer) 1
127.0.0.1:6379> get key_a
(nil)
127.0.0.1:6379>
?
?
过期的key
?
正常来说Redis的key是在没有过期时间的情况下创建的。除非用户显式的将这个key删除,否则这个key会永久存在。
?
EXPIRE命令可以给key关联一个过期时间,这会带来一些额外的内存消耗。当一个key设置了过期时间,Redis会确保在指定的时间过去时将这个key删除。
?
过期与持久性
key的过期信息是以unix时间戳存储的。为了让过期机制工作的更好,计算机时间必须保持稳定。如果将RDB文件在两台时钟有着很大不同步的计算机移动时,诡异的事情就可能发生,如key被加载时就已经过期了。
?
即使是正在运行的实例也会时钟检查计算机时钟,例如,如果设置了一个过期时间为1000秒的key,此时将计算的时钟往后调了2000秒,那么这个key就会立即过期,而不是1000秒之后过期。
?
Reids如何处理过期的key
Redis有两种方式去处理过期的key:主动(active way)和被动(passive way)。
?
- 被动过期(passive way):
- 当客户的尝试去访问一个过期了的key,此时这个key会被删除,并且返回一个nil。
- 主动过期(active way):
- 有些key可能永远不会在被访问到,但是无论如何这些key都应该过期,Redis会定期的在设置了过期时间的key中随机挑选测试一些key,已过期的key会从keyspace中删除。
- Redis每秒会执行10次下面的步骤:
- 在设置了过期时间的key中随机挑选20个key测试。
- 删除所有已过期的key。
- 如果有超过25%的key过期,重复第一步。
- 概率算法,假设样本代表整个key space,Redis继续过期直到可能过期的key百分比低于25%
- 在任意给定时刻,使用内存的已过期key的最大数量最大等于每秒最大写入操作数量除以 4。
?
?