4.2 生存时间

2016-03-19 02:37:00 4,183 0

4.2.1 命令介绍

在实际的开发中经常会遇到一些有时效的数据,比如限时优惠活动、缓存或验证码等,过了一定的时间就需要删除这些数据。在关系数据库中一般需要额外的一个字段记录到期时间,然后定期检测删除过期数据。而在Redis中可以使用EXPIRE命令设置一个键的生存时间,到时间后Redis会自动删除它。EXPIRE命令的使用方法为EXPIRE key seconds,其中seconds参数表示键的生存时间,单位是秒。如要想session:29e3d键在15分钟后被删除:

redis>SET session:29e3d uid1314
OK
redis>EXPIRE session:29e3d 900
(integer) 1

EXPIRE命令返回1表示设置成功,返回0则表示键不存在或设置失败。例如:

redis>DEL session:29e3d
(integer) 1
redis>EXPIRE session:29e3d 900
(integer) 0

如果想知道一个键还有多久的时间会被删除,可以使用TTL命令。返回值是键的剩余时间(单位是秒):

redis>SET foo bar
OK
redis>EXPIRE foo 20
(integer) 1
redis>TTL foo
(integer) 15
redis>TTL foo
(integer) 7
redis> TTL foo
(integer) -1

可见随着时间的不同,foo键的生存时间逐渐减少,20秒后foo键会被删除。当键不存在时TTL命令会返回1。另外同样会返回1的情况是没有为键设置生存时间(即永久存在,这是建立一个键后的默认情况):

redis>SET persistKey value
OK
redis>TTL persistKey
(integer) -1

如果想取消键的生存时间设置(即将键恢复成永久的),可以使用PERSIST命令。如果生存时间被成功清除则返回1;否则返回0(因为键不存在或键本来就是永久的):

redis>SET foo bar
OK
redis>EXPIRE foo 20
(integer) 1
redis>PERSIST foo
(integer) 1
redis>TTL foo
(integer) -1

除了PERSIST命令之外,使用SETGETSET命令为键赋值也会同时清除键的生存时间,例如:

redis>EXPIRE foo 20
(integer) 1
redis>SET foo bar
OK
redis>TTL foo
(integer) -1

使用EXPIRE命令会重新设置键的生存时间,就像这样:

redis>SET foo bar
OK
redis>EXPIRE foo 20
(integer) 1
redis>TTL foo
(integer) 15
redis>EXPIRE foo 20
(integer) 1
redis>TTL foo
(integer) 17

其他只对键值进行操作的命令(如INCR、LPUSH、HSET、ZREM)均不会影响键的生存时间。

EXPIRE命令的seconds参数必须是整数,所以最小单位是1秒。如果想要更精确的控制键的生存时间应该使用PEXPIRE命令,PEXPIRE命令与EXPIRE的唯一区别是前者的时间单位是毫秒,即PEXPIRE key 1000与EXPIRE key 1等价。对应地可以用PTTL命令以毫秒为单位返回键的剩余时间。

提示 如果使用WATCH命令监测了一个拥有生存时间的键,该键时间到期自动删除并不会被WATCH命令认为该键被改变。

另外还有两个相对不太常用的命令:EXPIREAT PEXPIREAT

EXPIREAT命令与EXPIRE命令的差别在于前者使用Unix时间作为第二个参数表示键的生存时间的截止时间。PEXPIREAT命令与EXPIREAT命令的区别是前者的时间单位是毫秒。例如:

redis>SET foo bar
OK
redis>EXPIREAT foo 1351858600
(integer) 1
redis>TTL foo
(integer) 142
redis>PEXPIREAT foo 1351858700000
(integer) 1

4.2.3 实现缓存

为了提高网站的负载能力,常常需要将一些访问频率较高但是对CPU或IO资源消耗较大的操作的结果缓存起来,并希望让这些缓存过一段时间自动过期。比如教务网站要对全校所有学生的各个科目的成绩汇总排名,并在首页上显示前10名的学生姓名,由于计算过程较耗资源,所以可以将结果使用一个Redis的字符串键缓存起来。由于学生成绩总在不断地变化,需要每隔两个小时就重新计算一次排名,这可以通过给键设置生存时间的方式实现。每次用户访问首页时程序先查询缓存键是否存在,如果存在则直接使用缓存的值;否则重新计算排名并将计算结果赋值给该键并同时设置该键的生存时间为两个小时。伪代码如下:

rank=GET cache:rank
if not rank
rank=计算排名...
MUlTI
SET cache:rank, rank
EXPIRE cache:rank, 7200
EXEC

然而在一些场合中这种方法并不能满足需要。当服务器内存有限时,如果大量地使用缓存键且生存时间设置得过长就会导致Redis占满内存;另一方面如果为了防止Redis占用内存过大而将缓存键的生存时间设得太短,就可能导致缓存命中率过低并且大量内存白白地闲置。

实际开发中会发现很难为缓存键设置合理的生存时间,为此可以限制Redis能够使用的最大内存,并让Redis按照一定的规则淘汰不需要的缓存键,这种方式在只将Redis用作缓存系统时非常实用。

具体的设置方法为:修改配置文件的maxmemory参数,限制Redis最大可用内存大小(单位是字节),当超出了这个限制时Redis会依据maxmemory-policy参数指定的策略来删除不需要的键,直到Redis占用的内存小于指定内存。

maxmemory-policy支持的规则如表4-1所示。其中的LRU(Least Recently Used)算法即“最近最少使用”,其认为最近最少使用的键在未来一段时间内也不会被用到,即当需要空间时这些键是可以被删除的。

QQ截图20160318152455.png

如当maxmemory-policy设置为allkeys-lru时,一旦Redis占用的内存超过了限制值,Redis会不断地删除数据库中最近最少使用的键① ,直到占用的内存小于限制值。

注释:①事实上Redis并不会准确地将整个数据库中最久未被使用的键删除,而是每次从数据库中随机取3个键并删除这3个键中最久未被使用的键。删除生存时间最接近的键的实现方法也是这样。“3”这个数字可以通过Redis的配置文件中的maxmemory-samples参数设置。

http://ifeve.com/redis-lru/

上一篇:4.1 事务 下一篇:4.3 排序