您的位置:首页 > 数据库 > Redis

Redis数据过期策略探究

2016-09-30 15:54 721 查看
通过EXPIRE key seconds命令来设置数据的过期时间。返回1表明设置成功,返回0表明key不存在或者不能成功设置过期时间。在key上设置了过期时间后key将在指定的秒数后被自动删除。被指定了过期时间的key在Redis中被称为是不稳定的。当key被DEL命令删除或者被SET、GETSET命令重置后与之关联的过期时间会被清除。
[plain] view plain copy 



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字段的值都不会影响过期时间。注:EXPIRE key seconds为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。在 Redis 中,带有生存时间的 key 被称为『易失的』(volatile)。生存时间可以通过使用 DEL 命令来删除整个 key 来移除,或者被 SET 和 GETSET 命令覆写(overwrite),这意味着,如果一个命令只是修改(alter)一个带生存时间的 key 的值而不是用一个新的 key 值来代替(replace)它的话,那么生存时间不会被改变。比如说,对一个 key 执行 INCR 命令,对一个列表进行 LPUSH 命令,或者对一个哈希表执行 HSET 命令,这类操作都不会修改 key 本身的生存时间。另一方面,如果使用 RENAME 对一个 key 进行改名,那么改名后的 key 的生存时间和改名前一样。RENAME 命令的另一种可能是,尝试将一个带生存时间的 key 改名成另一个带生存时间的 another_key ,这时旧的 another_key (以及它的生存时间)会被删除,然后旧的 key 会改名为 another_key ,因此,新的 another_key 的生存时间也和原本的 key 一样。使用 PERSIST 命令可以在不删除 key 的情况下,移除 key 的生存时间,让 key 重新成为一个『持久的』(persistent) key 。更新生存时间可以对一个已经带有生存时间的 key 执行 EXPIRE 命令,新指定的生存时间会取代旧的生存时间。[plain] view plain copy 



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变为持久的。
[plain] view plain copy 



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。
[plain] view plain copy 



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的所有特性,包括过期时间设置。
[plain] view plain copy 



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上时原有的过期时间将被更新为新的过期时间
[plain] view plain copy 



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一样独立的进行过期处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: