首页 > 代码库 > Redis数据过期策略探究

Redis数据过期策略探究

通过EXPIRE key seconds命令来设置数据的过期时间。返回1表明设置成功,返回0表明key不存在或者不能成功设置过期时间。

在key上设置了过期时间后key将在指定的秒数后被自动删除。被指定了过期时间的key在Redis中被称为是不稳定的。

当key被DEL命令删除或者被SET、GETSET命令重置后与之关联的过期时间会被清除。
redis 127.0.0.1:6379> set mykey "test expire"
OK
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
redis 127.0.0.1:6379> ttl mykey
(integer) 97
redis 127.0.0.1:6379> ttl mykey
(integer) 93
redis 127.0.0.1:6379> set mykey "test expire reset"
OK
redis 127.0.0.1:6379> ttl mykey
(integer) -1

redis 127.0.0.1:6379> set mykey "test expire"
OK
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
redis 127.0.0.1:6379> ttl mykey
(integer) 98
redis 127.0.0.1:6379> ttl mykey
(integer) 91
redis 127.0.0.1:6379> getset mykey "test expire reset"
"test expire"
redis 127.0.0.1:6379> ttl mykey
(integer) -1
这也意味着仅从概念上更新了存储在key中的值而没有用全新的值替换key原有值的所有操作都不会影响在该key上设置的过期时间。例如使用INCR命令增加key的值或者通过LPUSH命令在list中增加一个新的元素或者使用HSET命令更新hash字段的值都会回清除原有的过期时间设置。
redis 127.0.0.1:6379> set mykey 1
OK
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
redis 127.0.0.1:6379> ttl mykey
(integer) 95
redis 127.0.0.1:6379> incr mykey
(integer) 2
redis 127.0.0.1:6379> ttl mykey
(integer) 77

redis 127.0.0.1:6379> lpush listkey 1
(integer) 1
redis 127.0.0.1:6379> expire listkey 100
(integer) 1
redis 127.0.0.1:6379> ttl listkey
(integer) 94
redis 127.0.0.1:6379> lpush listkey 2
(integer) 2
redis 127.0.0.1:6379> ttl listkey
(integer) 82

redis 127.0.0.1:6379> hmset hashkey name "redis" passwd "redis"
OK
redis 127.0.0.1:6379> expire hashkey 100
(integer) 1
redis 127.0.0.1:6379> ttl hashkey
(integer) 95
redis 127.0.0.1:6379> hset hashkey  passwd "redis.vs.mysql"
(integer) 0
redis 127.0.0.1:6379> ttl hashkey
(integer) 66
当然也可通过PERSIST命令清除已设置的过期时间重新将key变为持久的。
redis 127.0.0.1:6379> set mykey 'test clear expire'
OK
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
redis 127.0.0.1:6379> ttl mykey
(integer) 96
redis 127.0.0.1:6379> persist mykey
(integer) 1
redis 127.0.0.1:6379> ttl mykey
(integer) -1
若key被RENAME命令重命名则与之关联的过期时间将传递到新名称的key。
redis 127.0.0.1:6379> get mykeynew
(nil)
redis 127.0.0.1:6379> set mykey 'test expire transfer'
OK
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
redis 127.0.0.1:6379> ttl mykey
(integer) 96
redis 127.0.0.1:6379> rename mykey mykeynew
OK
redis 127.0.0.1:6379> ttl mykey
(integer) -1
redis 127.0.0.1:6379> ttl mykeynew
(integer) 80
若key被RENAME命令重写,比如本存在名为mykey_a和mykey_b的key一个RENAME mykey_b mykey_a命令将mykey_b重命名为本已存在的mykey_a那么无论mykey_a原来的设置如何都将继承mykey_b的所有特性,包括过期时间设置。
redis 127.0.0.1:6379> set mykey_b 'b'
OK
redis 127.0.0.1:6379> set mykey_a 'a'
OK
redis 127.0.0.1:6379> expire mykey_b 100
(integer) 1
redis 127.0.0.1:6379> ttl mykey_b
(integer) 93
redis 127.0.0.1:6379> ttl mykey_a
(integer) -1
redis 127.0.0.1:6379> rename mykey_b mykey_a
OK
redis 127.0.0.1:6379> ttl mykey_b
(integer) -1
redis 127.0.0.1:6379> ttl mykey_a
(integer) 66
EXPIRE key seconds应用于一个已经设置了过期时间的key上时原有的过期时间将被更新为新的过期时间
redis 127.0.0.1:6379> set mykey 'test expire update'
OK
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
redis 127.0.0.1:6379> ttl mykey
(integer) 95
redis 127.0.0.1:6379> expire mykey 1000
(integer) 1
redis 127.0.0.1:6379> ttl mykey
(integer) 998

附录:
key的过期时间
通常,Redis key被创建时不会自动关联过期时间,key将长久存在,除非通过DEL等命令显示的删除。EXPIRE命令簇可以为指定的key关联一个过期时间,代价是一点额外的内存开销。当key被设置了过期时间后Redis要保证在超时时移除该key。key的过期时间可被EXPIRE命令更新或者被PERSIST命令完全移除。

过期时间的精度
Redis2.4中expire精度不高,通常在0到1秒间,Redis2.6以后expire精度可以控制在0到1毫秒内。

过期与持久化

key的过期信息以绝对Unix时间戳的形式存储(Redis2.6之后以毫秒级别的精度存储)。这意味着,即使Redis实例没有运行也不会对key的过期时间造成影响。
为了使过期时间更正确的工作,必须检查计算机的时间。如果将RDB快照从一台计算机移动到另一台时间超前或滞后的计算机便会发生好玩的事情,比如数据刚载入便超时。即使是在同一机器的同一实例中若计算机的时间不正确或发生了变化同样为引起问题,比如一批数据的过期时间被设置为了1000,之后计算机时间意外的快了2000秒,那么这些key将立刻过期,而不是1000秒后过期。

Redis如何使key过期
Redis key过期的方式有二:被动方式和主动方式
当clients试图访问设置了过期时间且已过期的key时,为主动过期方式。
但仅是这样是不够的,以为可能存在一些key永远不会被再次访问到,这些设置了过期时间的key也是需要在过期后被删除的。因此,Redis会周期性的随机测试一批设置了过期时间的key并进行处理。测试到的已过期的key将被删除。典型的方式为,Redis每秒做10次如下的步骤:
1.随机测试100个设置了过期时间的key
2.删除所有发现的已过期的key
3.若删除的key超过25个则重复步骤1
这是一个基于概率的简单算法,基本的假设是抽出的样本能够代表整个key空间,redis持续清理过期的数据直至将要过期的key的百分比降到了25%以下。这也意味着在任何给定的时刻已经过期但仍占据着内存空间的key的量最多为每秒的写操作量除以4.

replication link和AOF文件中的过期处理
为了获得正确的行为而不至于导致一致性问题,当一个key过期时DEL操作将被记录在AOF文件并传递到所有相关的slave。也即过期删除操作统一在master实例中进行并向下传递,而不是各salve各自掌控。这样一来便不会出现数据不一致的情形。当slave连接到master后并不能立即清理已过期的key(需要等待由master传递过来的DEL操作),slave仍需对数据集中的过期状态进行管理维护以便于在slave被提升为master会能像master一样独立的进行过期处理。

Redis数据过期策略探究