EXPIRE、PEXPIRE:设置生存时间

用户可以通过执行EXPIRE命令或者PEXPIRE命令为键设置一个生存时间(Time To Live,TTL):键的生存时间在设置之后就会随着时间的流逝而不断地减少,当一个键的生存时间被消耗殆尽时,Redis就会移除这个键。

Redis提供了EXPIRE命令用于设置秒级精度的生存时间,它可以让键在指定的秒数之后自动被移除:

EXPIRE key seconds

而PEXPIRE命令则用于设置毫秒级精度的生存时间,它可以让键在指定的毫秒数之后自动被移除:

PEXPIRE key milliseconds

EXPIRE命令和PEXPIRE命令在生存时间设置成功时返回1;如果用户给定的键并不存在,那么命令返回0表示设置失败。

以下是一个使用EXPIRE命令的例子:

redis> SET msg "hello world"
OK
redis> EXPIRE msg 5
(integer) 1
redis> GET msg -- 在5s之内访问,键存在
"hello world"
redis> GET msg -- 在5s之后访问,键不再存在
(nil)

上面的代码通过执行EXPIRE命令为msg键设置了5s的生存时间:

  • 如果我们在5s之内访问msg键,那么Redis将返回msg键的值"hello world"。

  • 如果我们在5s之后访问msg键,那么Redis将返回一个空值,因为msg 键已经自动被移除了。

表12-1展示了msg键从设置生存时间到被移除的整个过程。

image 2025 01 05 15 53 04 475
Figure 1. 表12-1 msg键从设置生存时间到被移除的整个过程

以下则是一个使用PEXPIRE命令的例子:

redis> SET number 10086
OK
redis> PEXPIRE number 6500
(integer) 1
redis> GET number -- 在6500ms(即6.5s)之内访问,键存在
"10086"
redis> GET number -- 在6500ms之后访问,键不再存在
(nil)

表12-2展示了number键从设置生存时间到被移除的整个过程。

image 2025 01 05 15 53 48 334
Figure 2. 表12-2 number键从设置生存时间到被移除的整个过程

更新键的生存时间

当用户对一个已经带有生存时间的键执行EXPIRE命令或PEXPIRE命令时,键原有的生存时间将会被移除,并设置新的生存时间。

举个例子,如果我们执行以下命令,将msg键的生存时间设置为10s:

redis> EXPIRE msg 10
(integer) 1

然后在10s之内执行以下命令:

redis> EXPIRE msg 50
(integer) 1

那么msg键的生存时间将被更新为50s,并重新开始倒数,表12-3展示了这个更新过程。

image 2025 01 05 15 55 03 186
Figure 3. 表12-3 msg键生存时间的更新过程

其他信息

  • 复杂度:EXPIRE命令和PEXPIRE命令的复杂度都为O(1)。

  • 版本要求:EXPIRE命令从Redis 1.0.0版本开始可用,PEXPIRE命令从 Redis 2.6.0版本开始可用。

示例:带有自动移除特性的缓存程序

用户在使用缓存程序的时候,必须考虑缓存的时效性:对于内容不断变换的应用来说,一份缓存存在的时间越长,它与实际内容之间的差异往往也就越大,因此为了让缓存能够及时地反映真实的内容,程序必须定期对缓存进行更新。

第2章曾展示过如何使用字符串键构建缓存程序,但那个缓存程序有一个明显的缺陷,那就是它无法自动移除过时的缓存。如果我们真的要在实际中使用那个程序,就必须再编写一个辅助程序来定期地删除旧缓存,这样一来使用缓存将会变得非常麻烦。

幸运的是,通过使用Redis的键过期功能,我们可以为缓存程序加上自动移除特性,并通过这个特性自动移除过期的、无效的缓存。

代码清单12-1展示了一个能够为缓存设置最大有效时间的缓存程序,这个程序与第2章展示的缓存程序的绝大部分代码都是相同的,主要区别在于,新程序除了会把指定的内容缓存起来之外,还会使用 EXPIRE 命令为缓存设置生存时间,从而使缓存可以在指定时间到达之后自动被移除。

代码清单12-1 带有自动移除特性的缓存程序:/expire/unsafe_volatile_cache.py
class VolatileCache:

    def __init__(self, client):
        self.client = client

    def set(self, key, value, timeout):
        """
        把数据缓存到键 key 里面,并为其设置过期时间。
        如果键 key 已经有值,那么使用新值去覆盖旧值。
        """
        self.client.set(key, value)
        self.client.expire(key, timeout)

    def get(self, key):
        """
        获取键 key 储存的缓存数据。
        如果键不存在,又或者缓存已经过期,那么返回 None 。
        """
        return self.client.get(key)

以下代码简单地展示了这个缓存程序的使用方法:

>>> from redis import Redis
>>> from unsafe_volatile_cache import VolatileCache
>>> client = Redis(decode_responses=True)
>>> cache = VolatileCache(client)
>>> cache.set("homepage", "<html><p>hello world</p></html>", 10) # 设置缓存
>>> cache.get("homepage") # 这个缓存在10s之内有效
'<html><p>hello world</p></html>'
>>> cache.get("homepage") # 10s过后,缓存自动被移除
>>>