EXPIRE

用法
EXPIRE key seconds [ NX | XX | GT | LT ]
复杂度
O(1)
始于
1.0.0
ACL 类别
@keyspace, @write, @fast

key 设置超时时间。超时时间到期后,该 key 将自动删除。在 Valkey 术语中,带有关联超时的 key 通常被称为易失性的。

超时时间只会被删除或覆盖 key 内容的命令清除,包括 DELSETGETSET 以及所有 *STORE 命令。这意味着所有概念上改变 key 中存储的值而不替换为新值的操作,都将保持超时时间不变。例如,使用 INCR 递增 key 的值,使用 LPUSH 将新值推入列表,或使用 HSET 更改哈希的字段值,所有这些操作都不会影响超时时间。

超时时间也可以通过使用 PERSIST 命令清除,从而将 key 恢复为持久化 key。

如果 key 使用 RENAME 重命名,则关联的生存时间会转移到新的 key 名。

如果 key 被 RENAME 覆盖,例如现有的 key Key_ARENAME Key_B Key_A 调用覆盖,则无论原始 Key_A 是否关联了超时时间,新的 key Key_A 都将继承 Key_B 的所有特性。

请注意,调用 EXPIRE/PEXPIRE 时指定非正数超时,或调用 EXPIREAT/PEXPIREAT 时指定过去的时间,将导致 key 被删除而不是过期(相应地,发出的key 事件将是 del,而不是 expired)。

选项

EXPIRE 命令支持一组选项

  • NX -- 仅当 key 没有过期时间时才设置过期时间
  • XX -- 仅当 key 已存在过期时间时才设置过期时间
  • GT -- 仅当新的过期时间大于当前过期时间时才设置过期时间
  • LT -- 仅当新的过期时间小于当前过期时间时才设置过期时间

对于 GTLT,非易失性 key 被视为无限 TTL。GTLTNX 选项是互斥的。

刷新过期时间

可以使用已设置过期时间的 key 作为参数调用 EXPIRE。在这种情况下,key 的生存时间会更新为新值。这有很多有用的应用,例如在下面的导航会话模式部分中记录的示例。

对于已设置超时时间的 key,EXPIRE 将返回 0 且不更改超时时间。

示例

127.0.0.1:6379> SET mykey "Hello"
OK
127.0.0.1:6379> EXPIRE mykey 10
(integer) 1
127.0.0.1:6379> TTL mykey
(integer) 10
127.0.0.1:6379> SET mykey "Hello World"
OK
127.0.0.1:6379> TTL mykey
(integer) -1
127.0.0.1:6379> EXPIRE mykey 10 XX
(integer) 0
127.0.0.1:6379> TTL mykey
(integer) -1
127.0.0.1:6379> EXPIRE mykey 10 NX
(integer) 1
127.0.0.1:6379> TTL mykey
(integer) 10

模式:导航会话

假设你有一个 Web 服务,你对用户最近访问的最新 N 个页面感兴趣,条件是每个相邻页面浏览之间的时间间隔不超过 60 秒。从概念上讲,你可以将这组页面浏览视为用户的导航会话,其中可能包含关于他或她当前正在寻找哪种产品的信息,以便你可以推荐相关产品。

你可以使用以下策略在 Valkey 中轻松建模此模式:每当用户进行页面浏览时,你都调用以下命令

MULTI
RPUSH pagewviews.user:<userid> http://.....
EXPIRE pagewviews.user:<userid> 60
EXEC

如果用户空闲超过 60 秒,key 将被删除,并且只有后续页面浏览时间差小于 60 秒的才会被记录。

这个模式可以很容易地修改为使用 INCR 代替 RPUSH 来使用计数器。

附录:Valkey 过期

带有过期时间的 key

通常 Valkey key 在创建时没有关联生存时间。该 key 将永远存在,除非用户通过显式方式删除它,例如使用 DEL 命令。

EXPIRE 系列命令能够为给定 key 关联一个过期时间,代价是 key 会使用一些额外的内存。当 key 设置了过期时间后,Valkey 会确保在指定时间到期时删除该 key。

key 的生存时间可以使用 EXPIREPERSIST 命令(或其它严格相关的命令)更新或完全移除。

过期精度

过期误差为 0 到 1 毫秒。

过期和持久化

key 的过期信息以毫秒为单位存储。这意味着即使 Valkey 实例不活动,时间也在流逝。

为了使过期正常工作,计算机时间必须保持稳定。如果你从两台时钟严重不同步的计算机移动 RDB 文件,可能会发生一些奇怪的事情(例如所有加载的 key 在加载时就已过期)。

即使是运行中的实例也会一直检查计算机时钟,所以例如你设置一个 key 的生存时间为 1000 秒,然后将你的计算机时间向前调整 2000 秒,这个 key 将会立即过期,而不是持续 1000 秒。

Valkey 如何回收过期 key

Valkey 通过两种方式回收过期 key:访问时和在后台(即“主动过期 key”循环中)。访问时过期是指客户端尝试访问一个已超时过期的 key。该 key 在此次访问尝试时被删除。

仅依靠访问时过期是不够的,因为有些过期 key 可能永远不会再被访问。为了解决这个问题,Valkey 使用了名为“主动过期 key”工作的后台过期算法。该算法是自适应的:如果需要回收的过期 key 较少,它会尝试使用较少的 CPU。否则,它会变得更激进,尝试通过在更短的运行时间内回收更多 key 来释放更多内存,但会使用更多 CPU。

其工作原理如下

Valkey 缓慢扫描键空间以识别和回收过期键。这种“慢周期”是收集过期键的主要方式,并以服务器的赫兹频率(通常为 10 赫兹)运行。在慢周期期间,Valkey 允许内存中过期的键不超过 10%,并尝试最大使用 25% 的 CPU 功率。如果用户更改了主动过期键的配置,这些默认值会进行调整。

如果在慢周期后过期 key 的数量仍然很高,则主动过期 key 工作将进入“快周期”,尝试做更少的工作但更频繁。快周期运行时间不超过 1000 微秒,并以相同的间隔重复。在快周期期间,一旦数据库中已过期 key 的数量估计低于 10%,就会中断对每个数据库的检查。这样做是为了避免做太多工作却只获得太少的内存。

您可以在配置文件中通过 active-expire-effort 参数修改主动过期键工作,最大值为 10。默认的 active-expire-effort 值为 1,其基础值如下所示

  • ACTIVE_EXPIRE_CYCLE_KEYS_PER_LOOP = 20 - 每个 DB 循环的键数量。
  • ACTIVE_EXPIRE_CYCLE_FAST_DURATION = 1000 – 快速循环的最大持续时间(微秒)。
  • ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC = 25 – 慢循环期间最大 CPU 使用百分比。
  • ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE = 10 – 内存中可容忍的过期键最大百分比。

更改 active-expire-effort 值会导致内存中容忍的过期键百分比降低。然而,这会导致更长的循环和更高的 CPU 使用率,这可能会引入延迟。

要计算新值,请使用以下公式

  • ACTIVE_EXPIRE_CYCLE_KEYS_PER_LOOP + (ACTIVE_EXPIRE_CYCLE_KEYS_PER_LOOP / 4 * (effort - 1))
  • ACTIVE_EXPIRE_CYCLE_FAST_DURATION + (ACTIVE_EXPIRE_CYCLE_FAST_DURATION / 4 * (effort - 1))
  • ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC + (2 * (effort - 1))
  • ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE - (effort - 1)

其中 ACTIVE_EXPIRE_CYCLE_KEYS_PER_LOOPACTIVE_EXPIRE_CYCLE_FAST_DURATIONACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERCACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE 是基值,effort 是指定的 active-expire-effort

为了在不牺牲一致性的情况下获得正确的行为,当 key 过期时,将在 AOF 文件中生成一个 DEL 操作,并传播到所有连接的副本节点。通过这种方式,过期过程集中在主实例中,从而避免了一致性错误的发生。

然而,虽然连接到主实例的副本不会独立地使 key 过期(而是等待来自主实例的 DEL 命令),它们仍然会获取数据集中存在的过期key的完整状态,因此当副本被选为主实例时,它将能够独立地使 key 过期,完全作为主实例运行。

RESP2/RESP3 回复

以下之一

  • 整数回复: 0 如果超时未设置;例如,key 不存在,或由于提供的参数导致操作被跳过。

  • 整数回复: 1 如果超时已设置。

历史

版本 变更
7.0.0

新增选项:NXXXGTLT