INCREX

将键的数值增加一个数字并设置其过期时间。如果键不存在,则使用 0 作为初始值。

语法

INCREX key [BYFLOAT increment | BYINT increment] [LBOUND lowerbound] [UBOUND upperbound] [SATURATE] [EX seconds | PX milliseconds | EXAT unix-time-seconds| PXAT unix-time-milliseconds | PERSIST] [ENX]

引入版本:8.8.0

复杂度摘要:O(1)

在单个原子操作中,将 key 中存储的数值增加或减少指定的量,并具有可选的上限/下限和过期控制。如果该键不存在,则在执行操作之前将其设置为 0。如果键包含错误类型的值或无法解释为数字的字符串,则会返回错误。

与 INCR 和 INCRBY 不同,INCREX 返回一个包含两个元素的数组:增量后键的新值和实际应用的增量。当计算结果超出显式 LBOUND/UBOUND 或类型限制时,默认情况下会跳过该操作并使用 [current_value, 0] 进行回复,同时保持键及其 TTL 不变。 SATURATE 标志改变了这种行为,因此结果被限制在边界处。

必需参数

key

要递增的键的名称。

可选参数

BYFLOAT increment | BYINT increment

指定增量数量和类型:

  • BYFLOAT increment:将值增加给定的 long-double float。键的现有值可以是整数或浮点数,因为整数可以无损地提升为浮点数。会产生 NaN 或 Infinity 的结果将被拒绝。
  • BYINT increment:将值增加给定的 64 位有符号整数。增量可以是负值以减少值。 BYINT 要求键的现有值是整数类型;存储的浮点数(例如 "1.5")无法解析回整数。这与 INCR/INCRBY(仅整数)和 INCRBYFLOAT(两者都接受)一致。

如果未指定 BYFLOAT 和 BYINT,则键以整数模式递增 1。 BYFLOAT 和 BYINT 是互斥的。

LBOUND lowerbound

设置结果值的下限。如果计算结果低于 lowerbound,则跳过该操作,回复为 [current_value, 0](或使用 SATURATE 标志将结果置于 lowerbound)。省略时,界限为整数模式下的 LLONG_MIN 或 BYFLOAT 模式下的界限为 -LDBL_MAX。当指定了两者时,LBOUND 必须小于或等于 UBOUND。

UBOUND upperbound

设置结果值的上限。如果计算结果超过 upperbound,则跳过该操作并回复 [current_value, 0](或使用 SATURATE 标志将结果限制在 upperbound)。省略时,界限为整数模式下的 LLONG_MAX 或 BYFLOAT 模式下的界限为 LDBL_MAX。当两者都指定时,UBOUND 必须大于或等于 LBOUND。

SATURATE

指定后,越界结果的上限为 UBOUND 或下限为 LBOUND(或者在未给出显式界限时饱和到类型限制)。回复的第二个元素反映了饱和增量。如果增量在整数模式下无法表示为 64 位有符号整数,或者在 BYFLOAT 模式下会产生无穷大,则会返回错误。任何到期选项仍按指定应用。

边界违规包括超出显式 LBOUND/UBOUND 以及在未给出显式边界时溢出类型限制。

expiration flags

INCREX 命令支持一组修改其过期行为的选项:

  • EX seconds:设置指定的过期时间,单位为秒(正整数)。
  • PX milliseconds:设置指定的过期时间,单位为毫秒(正整数)。
  • EXAT unix-time-seconds:设置键过期的指定 Unix 时间(以秒为单位)(正整数)。
  • PXAT unix-time-milliseconds:设置键过期的指定 Unix 时间(以毫秒为单位)(正整数)。
  • PERSIST:删除与键相关的过期时间。

如果没有给出过期选项,则保留键的现有 TTL(如果有)。

ENX

仅当键当前没有 TTL/过期时才设置 TTL/过期。如果键已有 TTL,则仍应用增量,但 TTL 保持不变。 ENX 可以确保窗口计数器速率限制器的 TTL 仅在创建时设置,并且不会在后续令牌请求时重置。ENX 必须​​与 EX、PX、EXAT 或 PXAT 组合,并且与 PERSIST 不兼容。

示例

默认增量(按1),如果key不存在则从0开始:

redis> DEL mykey1
(integer) 0
redis> INCREX mykey1
1) (integer) 1
2) (integer) 1
redis> INCREX mykey1
1) (integer) 2
2) (integer) 1

使用 BYINT 递增特定整数,包括负递增递减:

redis> SET mykey2 100
OK
redis> INCREX mykey2 BYINT 5
1) (integer) 105
2) (integer) 5
redis> INCREX mykey2 BYINT -10
1) (integer) 95
2) (integer) -10

使用 BYFLOAT 以浮点数递增:

redis> SET mykey3 1.5
OK
redis> INCREX mykey3 BYFLOAT 0.25
1) "1.75"
2) "0.25"

使用 EX 设置每个增量的过期时间:

redis> DEL mykey4
(integer) 0
redis> INCREX mykey4 BYINT 1 EX 100
1) (integer) 1
2) (integer) 1
redis> TTL mykey4
(integer) 100

仅当键没有现有 TTL 时,才使用 ENX 设置过期时间。无论以下情况,始终都会应用增量:

redis> SET mykey5 10
OK
redis> INCREX mykey5 BYINT 1 EX 100 ENX
1) (integer) 11
2) (integer) 1
redis> TTL mykey5
(integer) 100
redis> SET mykey5 10 EX 500
OK
redis> INCREX mykey5 BYINT 1 EX 10 ENX
1) (integer) 11
2) (integer) 1
redis> TTL mykey5
(integer) 500

使用 PERSIST 在递增时删除键的过期时间:

redis> SET mykey6 5 EX 1000
OK
redis> TTL mykey6
(integer) 1000
redis> INCREX mykey6 BYINT 1 PERSIST
1) (integer) 6
2) (integer) 1
redis> TTL mykey6
(integer) -1

当结果超出 UBOUND 时,将默认越界行为与 SATURATE 进行比较。默认情况下,该键保持不变,并且回复报告零增量;使用 SATURATE,结果被限制在边界处,并且回复反映了饱和增量:

redis> SET mykey7 99
OK
redis> INCREX mykey7 BYINT 5 UBOUND 100
1) (integer) 99
2) (integer) 0
redis> SET mykey7 99
OK
redis> INCREX mykey7 BYINT 5 UBOUND 100 SATURATE
1) (integer) 100
2) (integer) 1

详细说明

模式:窗口计数器速率限制器

常见的速率限制模式需要原子地递增计数器并设置其过期时间。对于普通 INCR 和 EXPIRE,这通常要求 Lua 脚本是原子的。

INCREX 需要单个本机命令。 UBOUND 强制执行速率上限 — 默认情况下,一旦达到上限,操作就会被跳过 — 并且 ENX 确保如果前一个窗口已过期,则创建具有正确持续时间的新窗口;如果窗口已经存在,则不会扩展它。当计数器已达到上限时,actual_increment 为 0,为调用者提供即时反馈,无需额外读取或错误处理:

new_val, actual_incr = redis.execute_command(
    "INCREX", f"ratelimit:{user_id}",
    "BYINT", 1, "UBOUND", 100,
    "EX", 60, "ENX",
)
if actual_incr == 0:
    reject_request()  # rate limit exceeded

双活数据库

在主动-主动数据库中,每个副本根据其自己的本地值强制执行 LBOUND 和 UBOUND。不同副本同时接受的增量可以在副本同步后将合并值推至 UBOUND 以上或低于 LBOUND。当合并的值超出范围时,每个副本都会拒绝进一步的增量,直到该值返回到范围内或键过期。

例如,有两个副本和一个从 0 开始的键:

Replica 1: INCREX k BYINT 6 UBOUND 10   ->  1) 6  2) 6
Replica 2: INCREX k BYINT 6 UBOUND 10   ->  1) 6  2) 6
After synchronization, both replicas:       k = 12

每个副本接受其增量,因为其本地结果 6 在界限内。合并后的值 12 超过 UBOUND。

Redis Software 与 Redis Cloud 兼容性

Redis
软件
Redis
Cloud
说明
✅ 标准
✅ 主动-主动*
❌ 标准
❌主动-主动
*在主动-主动数据库中,副本对其本地值强制执行边界,因此合并的值可能会超出它们。请参阅 双活数据库。

返回值

RESP2

数组回复:二元素数组:

  1. 新价值 — 递增后键的值,或者当越界结果导致操作被跳过时不变的当前值。
  2. 实际增量 — 实际应用的增量。当 SATURATE 将结果限制在某个界限时,可能与请求的增量不同;当超出界限的结果导致操作被跳过时,始终为 0。

两个元素在整数模式下均为 整数回复(默认为 BYINT),在 BYFLOAT 模式下为表示浮点值的 批量字符串回复。

RESP3

数组回复:二元素数组:

  1. 新价值 — 递增后键的值,或者当越界结果导致操作被跳过时不变的当前值。
  2. 实际增量 — 实际应用的增量。当 SATURATE 将结果限制在某个界限时,可能与请求的增量不同;当超出界限的结果导致操作被跳过时,始终为 0。

两个元素在整数模式下均为 整数回复(默认或 BYINT),在 BYFLOAT 模式下均为 双重回复。

资料来源:Redis 官方 INCREX 文档;中文内容参考 Redis 文档许可。