Redis数据过时策略探究

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

在key上设置了过时时间后key将在指定的秒数后被自动删除。被指定了过时时间的key在Redis中被称为是不稳定的。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字段的值都会回清除原有的过时时间设置。sql

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。code

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同样独立的进行过时处理。get

相关文章
相关标签/搜索