COPY
从 6.2.0 开始可用。
时间复杂度:集合的 O(N) 最坏情况,其中 N 是嵌套项的数量。O(1) 用于字符串值。
此命令将存储在source键中的值复制到destination 键中。
默认情况下,destination密钥是在连接使用的逻辑数据库中创建的。该DB选项允许为目标键指定替代逻辑数据库索引。
destination当密钥已经存在时,该命令会返回错误。该 REPLACE选项destination在将值复制到它之前删除键。
返回值
整数回复,具体来说:
- 1如果source被复制。
- 0如果source没有被复制。
例子
SET dolly "sheep"
COPY dolly clone
GET clone
DEL
从 1.0.0 开始可用。
时间复杂度: O(N),其中 N 是要移除的键的数量。当要删除的键包含字符串以外的值时,该键的单个复杂度为 O(M),其中 M 是列表、集合、排序集或散列中的元素数。删除包含字符串值的单个键是 O(1)。
删除指定的键。如果键不存在,则忽略它。
返回值
整数回复:已删除的键数。
redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> DEL key1 key2 key3
(integer) 2
redis>
DUMP
从 2.6.0 开始可用。
时间复杂度: O(1) 访问键和额外的 O(NM) 序列化它,其中 N 是组成值的 Redis 对象的数量,M 是它们的平均大小。对于小字符串值,时间复杂度因此为 O(1)+O(1M),其中 M 很小,因此只需 O(1)。
以 Redis 特定的格式序列化存储在 key 中的值并将其返回给用户。可以使用RESTORE 命令将返回的值合成回 Redis 键。
序列化格式是不透明且非标准的,但它具有一些语义特征:
- 它包含一个 64 位校验和,用于确保检测到错误。RESTORE命令确保在使用序列化值合成密钥之前检查校验和。
- 值以 RDB 使用的相同格式编码。
- 一个 RDB 版本被编码在序列化值内部,因此 RDB 格式不兼容的不同 Redis 版本将拒绝处理序列化值。
序列化值不包含过期信息。为了捕获当前值的生存时间,应使用PTTL命令。
如果key不存在,则返回 nil 批量回复。
返回值
批量字符串回复:序列化值。
例子
redis> SET mykey 10
"OK"
redis> DUMP mykey
"\u0000\xC0\n\n\u0000n\x9FWE\u000E\xAEc\xBB"
redis>
EXISTS
从 1.0.0 开始可用。
时间复杂度: O(N),其中 N 是要检查的键的数量。
如果key存在则返回。
用户应该知道,如果在参数中多次提到相同的现有密钥,它将被计算多次。所以如果somekey存在,EXISTS somekey somekey将返回 2。
返回值
整数回复,特别是指定为参数的键中存在的键数。
例子
redis> SET key1 "Hello"
"OK"
redis> EXISTS key1
(integer) 1
redis> EXISTS nosuchkey
(integer) 0
redis> SET key2 "World"
"OK"
redis> EXISTS key1 key2 nosuchkey
(integer) 2
redis>
历史
Redis 版本 >= 3.0.3:接受多个 key
参数。
EXPIRE
从 1.0.0 开始可用。
时间复杂度: O(1)
设置超时key。超时后,密钥将被自动删除。在 Redis 术语中,具有关联超时的键通常被称为volatile 。
只有删除或覆盖密钥内容的命令才能清除超时,包括DEL、SET、GETSET和所有*STORE 命令。这意味着所有在概念上更改存储在键中的值而不用新值替换它的操作都将保持超时不变。例如,使用INCR增加键的值,使用LPUSH将新值推送到列表中,或者使用HSET更改哈希的字段值都是不会影响超时的操作。
也可以清除超时,使用PERSIST命令将密钥重新变为持久密钥。
如果使用RENAME重命名密钥,则关联的生存时间将转移到新的密钥名称。
如果键被RENAME覆盖,就像现有键Key_A 被调用覆盖一样RENAME Key_B Key_A,无论原始键是否Key_A关联超时,新键Key_A都将继承 的所有特征Key_B。
请注意,使用非正超时 调用EXPIRE / PEXPIRE或使用过去时间调用EXPIREAT / PEXPIREAT将导致键被 删除而不是过期(因此,发出的键事件 将是del,而不是expired)。
选项
EXPIRE命令支持一组选项:
- NX-- 只有当密钥没有过期时才设置过期
- XX-- 仅当密钥已过期时才设置过期
- GT-- 仅当新的到期时间大于当前到期时间时才设置到期时间
- LT-- 仅在新到期时间小于当前到期时设置到期
非易失性密钥被视为无限 TTLGT和LT。,GT和选项是互斥的LT。NX
刷新过期
可以使用已经具有现有过期集的键作为参数来调用EXPIRE 。在这种情况下,密钥的生存时间会更新为新值。有许多有用的应用程序,下面的 导航会话模式部分记录了一个示例。
Redis 2.1.3 之前的差异
在 Redis 2.1.3之前的版本中,使用更改其值的命令更改设置了过期时间的键具有完全删除该键的效果。由于复制层的限制现已修复,因此需要此语义。
EXPIRE将返回 0 并且不会更改设置了超时的键的超时。
返回值
整数回复,具体来说:
- 1如果设置了超时。
- 0如果未设置超时。例如,键不存在,或者由于提供的参数而跳过了操作。
例子
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis> SET mykey "Hello World"
"OK"
redis> TTL mykey
(integer) -1
redis> EXPIRE mykey 10 XX
(integer) 0
redis> TTL mykey
(integer) -1
redis> EXPIRE mykey 10 NX
(integer) 1
redis> TTL mykey
(integer) 10
redis>
模式:导航会话
假设您有一个 Web 服务,并且您对 用户最近访问的最近 N 个页面感兴趣,这样每个相邻的页面视图都不会在前一个页面的 60 秒后执行。从概念上讲,您可以将这组页面视图视为用户的导航会话 ,其中可能包含有关他或她当前正在寻找哪种产品的有趣信息,以便您推荐相关产品。
您可以使用以下策略在 Redis 中轻松建模此模式:每次用户进行页面查看时,您调用以下命令:
MULTI
RPUSH pagewviews.user:<userid> http://.....
EXPIRE pagewviews.user:<userid> 60
EXEC
如果用户闲置超过 60 秒,则删除该键,仅记录相差小于 60 秒的后续页面浏览量。
此模式很容易修改为使用使用INCR的计数器而不是使用RPUSH的列表。
附录:Redis过期
过期的密钥
通常,创建 Redis 密钥时没有关联的生存时间。密钥将永远存在,除非用户以明确的方式将其删除,例如使用DEL命令。
EXPIRE系列命令能够将过期时间与给定的键相关联,但代价是该键使用了一些额外的内存。当一个键设置了过期时间时,Redis 将确保在指定的时间过去后删除该键。
可以使用EXPIRE和 PERSIST命令(或其他严格相关的命令)更新或完全删除关键生存时间。
过期精度
在 Redis 2.4 中,过期可能不是精确的,它可能在零到一秒之间。
从 Redis 2.6 开始,过期错误为 0 到 1 毫秒。
过期和持久性
密钥过期信息存储为绝对 Unix 时间戳(在 Redis 2.6 或更高版本的情况下以毫秒为单位)。这意味着即使 Redis 实例不活动,时间也在流逝。
为了使过期工作正常,计算机时间必须保持稳定。如果您从两台时钟严重不同步的计算机上移动 RDB 文件,可能会发生有趣的事情(例如所有加载的密钥在加载时都已过期)。
即使正在运行的实例也会始终检查计算机时钟,因此,例如,如果您将密钥的生存时间设置为 1000 秒,然后将您的计算机时间设置为未来 2000 秒,则该密钥将立即过期,而不是持续1000 秒。
Redis 如何使密钥过期
Redis 密钥以两种方式过期:被动方式和主动方式。
仅当某些客户端尝试访问密钥时,密钥就会被动过期,并且发现密钥已超时。
当然这还不够,因为有过期的密钥将永远不会被再次访问。这些密钥无论如何都应该过期,因此 Redis 会定期在设置过期的密钥中随机测试几个密钥。所有已经过期的键都会从键空间中删除。
具体来说,这是 Redis 每秒执行 10 次的操作:
- 从具有关联过期时间的密钥集中测试 20 个随机密钥。
- 删除所有发现过期的密钥。
- 如果超过 25% 的密钥过期,请从步骤 1 重新开始。
这是一个简单的概率算法,基本上假设我们的样本代表了整个密钥空间,并且我们继续过期直到可能过期的密钥百分比低于 25%
这意味着在任何给定时刻,使用内存的已过期密钥的最大数量等于每秒最大写入操作量除以 4。
复制链接和 AOF 文件中如何处理过期
为了在不牺牲一致性的情况下获得正确的行为,当一个 key 过期时,在 AOF 文件中合成一个DEL操作并获得所有附加的副本节点。这样过期过程集中在主实例中,不会出现一致性错误。
然而,虽然连接到主节点的副本不会独立地使密钥过期(但会等待来自主节点的DEL ),但它们仍将采用数据集中存在的过期的完整状态,因此当一个副本被选为主节点时它将能够独立地使密钥过期,完全充当主人。
历史
Redis 版本 >= 7.0.0:添加了选项:NX
、XX
、GT
和 LT
。
EXPIREAT
从 1.2.0 开始可用。
时间复杂度: O(1)
EXPIREAT与EXPIRE具有相同的效果和语义,但它不指定表示 TTL(生存时间)的秒数,而是使用绝对Unix 时间戳(自 1970 年 1 月 1 日以来的秒数)。过去的时间戳将立即删除密钥。
该命令的具体语义请参考 EXPIRE的文档。
背景
引入EXPIREAT是为了将 AOF 持久性模式的相对超时转换为绝对超时。当然,它可以直接用于指定给定的密钥应该在未来的给定时间到期。
选项
EXPIREAT命令支持一组选项:
- NX-- 只有当密钥没有过期时才设置过期
- XX-- 仅当密钥已过期时才设置过期
- GT-- 仅当新的到期时间大于当前到期时间时才设置到期时间
- LT-- 仅在新到期时间小于当前到期时设置到期
非易失性密钥被视为无限 TTLGT和LT。,GT和选项是互斥的LT。NX
返回值
整数回复,具体来说:
- 1如果设置了超时。
- 0如果未设置超时。例如,键不存在,或者由于提供的参数而跳过了操作。
例子
redis> SET mykey "Hello"
"OK"
redis> EXISTS mykey
(integer) 1
redis> EXPIREAT mykey 1293840000
(integer) 1
redis> EXISTS mykey
(integer) 0
redis>
历史
Redis 版本 >= 7.0.0:添加了选项:NX
、XX
、GT
和 LT
。
EXPIRETIME
自 7.0.0 起可用。
时间复杂度: O(1)
返回给定密钥将过期的绝对 Unix 时间戳(自 1970 年 1 月 1 日起)。
另请参阅PEXPIRETIME命令,它以毫秒分辨率返回相同的信息。
返回值
Integer reply : Expiration Unix 时间戳,以秒为单位,或者为表示错误的负值(参见下面的描述)。
- -1如果密钥存在但没有关联的过期时间,则该命令返回。
- -2如果密钥不存在,该命令将返回。
例子
redis> SET mykey "Hello"
"OK"
redis> EXPIREAT mykey 33177117420
(integer) 1
redis> EXPIRETIME mykey
ERR Unknown or disabled command 'EXPIRETIME'
redis>
KEYS
从 1.0.0 开始可用。
时间复杂度: O(N),其中 N 是数据库中的键数,假设数据库中的键名和给定模式的长度有限。
返回所有匹配的键pattern。
虽然此操作的时间复杂度为O(N),但常数时间相当低。例如,在入门级笔记本电脑上运行的 Redis 可以在 40 毫秒内扫描 100 万个密钥数据库。
警告:将KEYS视为只能在生产环境中极其小心地使用的命令。当它针对大型数据库执行时,它可能会破坏性能。此命令用于调试和特殊操作,例如更改键空间布局。不要在常规应用程序代码中使用KEYS 。如果您正在寻找一种在键空间子集中查找键的方法,请考虑使用SCAN或sets。
支持的全局样式模式:
- h?llo匹配hello,hallo并且hxllo
- h*llo比赛hllo和heeeello
- h[ae]llo匹配hello但hallo,不匹配hillo
- h[^e]llo匹配hallo, hbllo, ... 但不匹配hello
- h[a-b]llo比赛hallo和hbllo
\如果要逐字匹配特殊字符,请使用转义字符。
返回值
数组回复:匹配的键列表pattern。
例子
redis> MSET firstname Jack lastname Stuntman age 35
"OK"
redis> KEYS *name*
1) "lastname"
2) "firstname"
redis> KEYS a??
1) "age"
redis> KEYS *
1) "lastname"
2) "age"
3) "firstname"
redis>
MIGRATE
从 2.6.0 开始可用。
时间复杂度:这个命令实际上是在源实例中执行一次DUMP+DEL,在目标实例中执行一次RESTORE。有关时间复杂度,请参阅这些命令的页面。还执行了两个实例之间的 O(N) 数据传输。
以原子方式将密钥从源 Redis 实例传输到目标 Redis 实例。成功后,密钥将从原始实例中删除,并保证存在于目标实例中。
该命令是原子的,并在传输密钥所需的时间内阻塞两个实例,在任何给定时间,密钥似乎存在于给定实例或另一个实例中,除非发生超时错误。在 3.2 及更高版本中,通过将空字符串 ("") 作为键并添加子句,可以在对MIGRATE的一次调用中对多个键进行流水线化处理。KEYS
该命令在内部使用DUMP生成键值的序列化版本,并使用RESTORE来合成目标实例中的键。源实例充当目标实例的客户端。如果目标实例向RESTORE命令返回 OK ,则源实例使用DEL删除密钥。
超时指定与目标实例通信的任何时刻的最大空闲时间(以毫秒为单位)。这意味着操作不需要在指定的毫秒数内完成,但传输应该在不阻塞超过指定的毫秒数的情况下进行。
MIGRATE需要执行 I/O 操作并遵守指定的超时。当传输过程中出现 I/O 错误或达到超时时,操作将中止并IOERR返回特殊错误。发生这种情况时,可能出现以下两种情况:
- 密钥可能在两个实例上。
- 密钥可能仅在源实例中。
发生超时时密钥不可能丢失,但调用MIGRATE的客户端在发生超时错误时应检查密钥是否也存在于目标实例中并采取相应措施。
当返回任何其他错误时(以 开头ERR) , MIGRATE保证该键仍然只存在于原始实例中(除非同名的键也已经存在于目标实例中)。
如果源实例中没有要迁移的键,NOKEY则返回。因为在正常情况下可能会丢失密钥,例如从过期开始, NOKEY这不是错误。
使用单个命令调用迁移多个键
从 Redis 3.0.6 开始,MIGRATE支持一种新的批量迁移模式,该模式使用管道在实例之间迁移多个键,而不会产生往返时间延迟和使用单个MIGRATE调用移动每个键时的其他开销。
为了启用此表单,KEYS使用该选项,并将普通键 参数设置为空字符串。实际的键名将在KEYS参数本身之后提供,如下例所示:
MIGRATE 192.168.1.34 6379 "" 0 5000 KEYS key1 key2 key3
使用这种形式NOKEY时,仅当实例中不存在任何键时才返回状态代码,否则即使只存在一个键,也会执行命令。
选项
- COPY-- 不要从本地实例中删除密钥。
- REPLACE-- 替换远程实例上的现有密钥。
- KEYS-- 如果 key 参数是一个空字符串,该命令将改为迁移该KEYS选项后面的所有键(有关更多信息,请参见上一节)。
- AUTH-- 使用给定的密码对远程实例进行身份验证。
- AUTH2-- 使用给定的用户名和密码对进行身份验证(Redis 6 或更高版本的 ACL 身份验证样式)。
返回值
简单字符串回复:该命令在成功时返回 OK,或者NOKEY如果在源实例中没有找到键。
历史
Redis 版本 >= 3.0.0:添加了 COPY
和 REPLACE
选项。
Redis 版本 >= 3.0.6:添加了 KEYS
选项。
Redis 版本 >= 4.0.7:添加了 AUTH
选项。
Redis 版本 >= 6.0.0:添加了 AUTH2
选项。
MOVE
从 1.0.0 开始可用。
时间复杂度: O(1)
key从当前选定的数据库(请参阅SELECT )移动到指定的目标数据库。当key目标数据库中已经存在或源数据库中不存在时,它什么也不做。因此,可以将MOVE用作锁定原语。
返回值
整数回复,具体来说:
- 1如果key被移动。
- 0如果key没有移动
OBJECT ENCODING
从 2.2.3 开始可用。
时间复杂度: O(1)
返回存储在的 Redis 对象的内部编码
Redis 对象可以用不同的方式编码:
- 字符串可以编码为raw(普通字符串编码)或int(表示 64 位有符号间隔中的整数的字符串以这种方式编码以节省空间)。
- 列表可以编码为ziplist或linkedlist。这ziplist是用于为小列表节省空间的特殊表示。
- 集合可以编码为intset或hashtable。这intset是一种特殊编码,用于仅由整数组成的小集合。
- 哈希可以编码为ziplist或hashtable。这ziplist是一种用于小散列的特殊编码。
- 排序集可以编码为ziplist或skiplist格式。对于 List 类型的小排序集可以使用 进行特殊编码ziplist,而skiplist编码是适用于任何大小的排序集的编码。
一旦执行了使 Redis 无法保留节省空间的编码的操作,所有特殊编码的类型都会自动转换为通用类型。
返回值
批量字符串回复:对象的编码,或者nil如果密钥不存在
OBJECT FREQ
从 4.0.0 开始可用。
时间复杂度: O(1)
此命令返回存储在的 Redis 对象的对数访问频率计数器
该命令仅在maxmemory-policy配置指令设置为 LFU 策略之一时可用。
返回值
整数回复
计数器的值。
OBJECT IDLETIME
从 2.2.3 开始可用。
时间复杂度: O(1)
此命令返回自上次访问存储在 中的值以来的时间(以秒为单位)
该命令仅在maxmemory-policy配置指令未设置为 LFU 策略之一时可用。
返回值
整数回复
以秒为单位的空闲时间。
OBJECT REFCOUNT
从 2.2.3 开始可用。
时间复杂度: O(1)
此命令返回存储在的引用计数
返回值
整数回复
引用的数量。
PERSIST
从 2.2.0 开始可用。
时间复杂度: O(1)
删除现有的 timeout on key,将密钥从volatile(设置了过期时间的密钥)变为持久性(由于没有关联超时而永不过期的密钥)。
返回值
整数回复,具体来说:
- 1如果超时被删除。
- 0ifkey不存在或没有关联的超时。
例子
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis> PERSIST mykey
(integer) 1
redis> TTL mykey
(integer) -1
redis>
PEXPIRE
从 2.6.0 开始可用。
时间复杂度: O(1)
此命令的工作方式与EXPIRE完全相同,但密钥的生存时间以毫秒而不是秒为单位指定。
选项
自 Redis 7.0 起,PEXPIRE命令支持一组选项:
- NX-- 只有当密钥没有过期时才设置过期
- XX-- 仅当密钥已过期时才设置过期
- GT-- 仅当新的到期时间大于当前到期时间时才设置到期时间
- LT-- 仅在新到期时间小于当前到期时设置到期
非易失性密钥被视为无限 TTLGT和LT。,GT和选项是互斥的LT。NX
返回值
整数回复,具体来说:
- 1如果设置了超时。
- 0如果未设置超时。例如,键不存在,或者由于提供的参数而跳过了操作。
例子
redis> SET mykey "Hello"
"OK"
redis> PEXPIRE mykey 1500
(integer) 1
redis> TTL mykey
(integer) 2
redis> PTTL mykey
(integer) 1499
redis> PEXPIRE mykey 1000 XX
(integer) 1
redis> TTL mykey
(integer) 1
redis> PEXPIRE mykey 1000 NX
(integer) 0
redis> TTL mykey
(integer) 1
redis>
历史
- Redis 版本 >= 7.0.0:添加了选项:
NX
、XX
、GT
和LT
。
PEXPIREAT
从 2.6.0 开始可用。
时间复杂度: O(1)
PEXPIREAT与EXPIREAT具有相同的效果和语义,但密钥到期的 Unix 时间以毫秒而不是秒为单位指定。
选项
自 Redis 7.0 起,PEXPIREAT命令支持一组选项:
- NX-- 只有当密钥没有过期时才设置过期
- XX-- 仅当密钥已过期时才设置过期
- GT-- 仅当新的到期时间大于当前到期时间时才设置到期时间
- LT-- 仅在新到期时间小于当前到期时设置到期
非易失性密钥被视为无限 TTLGT和LT。,GT和选项是互斥的LT。NX
返回值
整数回复,具体来说:
- 1如果设置了超时。
- 0如果未设置超时。例如,键不存在,或者由于提供的参数而跳过了操作。
例子
redis> SET mykey "Hello"
"OK"
redis> PEXPIREAT mykey 1555555555005
(integer) 1
redis> TTL mykey
(integer) -2
redis> PTTL mykey
(integer) -2
redis>
历史
- Redis 版本 >= 7.0.0:添加了选项:
NX
、XX
、GT
和LT
。
PEXPIRETIME
自 7.0.0 起可用。
时间复杂度: O(1)
PEXPIRETIME与EXPIRETIME具有相同的语义,但以毫秒而不是秒为单位返回绝对的 Unix 过期时间戳。
返回值
Integer reply : Expiration 以毫秒为单位的 Unix 时间戳,或一个负值以表示错误(参见下面的描述)。
- -1如果密钥存在但没有关联的过期时间,则该命令返回。
- -2如果密钥不存在,该命令将返回。
例子
redis> SET mykey "Hello"
"OK"
redis> PEXPIREAT mykey 33177117420000
(integer) 1
redis> PEXPIRETIME mykey
ERR Unknown or disabled command 'PEXPIRETIME'
redis>
PTTL
从 2.6.0 开始可用。
时间复杂度: O(1)
与TTL一样,此命令返回具有过期设置的密钥的剩余生存时间,唯一的区别是TTL返回以秒为单位的剩余时间量,而PTTL以毫秒为单位返回剩余时间。
在 Redis 2.6 或更早版本中,-1如果密钥不存在或密钥存在但没有关联的过期时间,则该命令返回。
从 Redis 2.8 开始,发生错误时的返回值发生了变化:
- -2如果密钥不存在,该命令将返回。
- -1如果密钥存在但没有关联的过期,则该命令返回。
返回值
整数回复:以毫秒为单位的 TTL,或负值以指示错误(请参阅上面的描述)。
例子
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 1
(integer) 1
redis> PTTL mykey
(integer) 1000
redis>
历史
- Redis 版本 >= 2.8.0:添加了 -2 回复。
RANDOMKEY
从 1.0.0 开始可用。
时间复杂度: O(1)
从当前选择的数据库中返回一个随机键。
返回值
批量字符串回复:随机键,或者nil当数据库为空时。
RENAME
从 1.0.0 开始可用。
时间复杂度: O(1)
重命名key为newkey. key不存在时返回错误。如果newkey已经存在它会被覆盖,当这种情况发生时RENAME会执行一个隐式的DEL操作,所以如果删除的键包含一个非常大的值,即使RENAME本身通常是一个恒定时间的操作,它也可能导致高延迟。
在集群模式下,两者key和newkey必须在同一个哈希槽中,这意味着实际上只有具有相同哈希标签的键才能在集群中可靠地重命名。
返回值
简单的字符串回复
例子
redis> SET mykey "Hello"
"OK"
redis> RENAME mykey myotherkey
"OK"
redis> GET myotherkey
"Hello"
redis>
历史
- Redis 版本 >= 3.2.0:当源名称和目标名称相同时,该命令不再返回错误。
RENAMENX
从 1.0.0 开始可用。
时间复杂度: O(1)
重命名key为newkeyifnewkey尚不存在。key不存在时返回错误。
在集群模式下,两者key和newkey必须在同一个哈希槽中,这意味着实际上只有具有相同哈希标签的键才能在集群中可靠地重命名。
返回值
整数回复,具体来说:
- 1如果key重命名为newkey.
- 0如果newkey已经存在。
例子
redis> SET mykey "Hello"
"OK"
redis> SET myotherkey "World"
"OK"
redis> RENAMENX mykey myotherkey
(integer) 0
redis> GET myotherkey
"World"
redis>
历史
- Redis 版本 >= 3.2.0:当源名称和目标名称相同时,该命令不再返回错误。
RESTORE
从 2.6.0 开始可用。
时间复杂度: O(1) 创建新键,额外 O(NM) 重构序列化值,其中 N 是组成该值的 Redis 对象的数量,M 是它们的平均大小。对于小字符串值,时间复杂度因此为 O(1)+O(1M),其中 M 很小,因此只需 O(1)。然而,对于排序集值,复杂度是 O(NMlog(N)),因为将值插入排序集是 O(log(N))。
创建与通过反序列化提供的序列化值(通过DUMP获得)获得的值关联的键。
如果ttl为 0,则创建的密钥没有任何过期,否则设置指定的过期时间(以毫秒为单位)。
如果ABSTTL使用了修饰符,ttl则应表示密钥将过期的绝对 Unix 时间戳(以毫秒为单位)。
出于驱逐目的,您可以使用IDLETIMEorFREQ修饰符。有关详细信息,请参阅 对象。
RESTOREkey除非您使用REPLACE修饰符,否则当已经存在时将返回“目标键名称正忙”错误。
RESTORE检查 RDB 版本和数据校验和。如果它们不匹配,则返回错误。
返回值
简单字符串回复:该命令在成功时返回 OK。
例子
redis> DEL mykey
0
redis> RESTORE mykey 0 "\n\x17\x17\x00\x00\x00\x12\x00\x00\x00\x03\x00\
x00\xc0\x01\x00\x04\xc0\x02\x00\x04\xc0\x03\x00\
xff\x04\x00u#<\xc0;.\xe9\xdd"
OK
redis> TYPE mykey
list
redis> LRANGE mykey 0 -1
1) "1"
2) "2"
3) "3"
历史
- Redis 版本 >= 3.0.0:添加了
REPLACE
修饰符。 - Redis 版本 >= 5.0.0:添加了
ABSTTL
修饰符。 - Redis 版本 >= 5.0.0:添加了
IDLETIME
和FREQ
选项。
SCAN
自 2.8.0 起可用。
时间复杂度:每次调用 O(1)。O(N) 用于完整的迭代,包括足够的命令调用以使光标返回 0。N 是集合内的元素数。
SCAN命令和密切相关的命令SSCAN 、 HSCAN和ZSCAN用于增量迭代元素集合。
- SCAN迭代当前选定的 Redis 数据库中的一组键。
- SSCAN迭代 Sets 类型的元素。
- HSCAN迭代 Hash 类型的字段及其相关值。
- ZSCAN迭代排序集类型的元素及其相关分数。
由于这些命令允许增量迭代,每次调用仅返回少量元素,因此它们可以在生产中使用,而不会像KEYS或SMEMBERS这样的命令在调用时阻塞服务器很长时间(甚至几秒钟)。键或元素的大集合。
然而,虽然像SMEMBERS这样的阻塞命令能够在给定时刻提供属于 Set 的所有元素,但 SCAN 系列命令仅对返回的元素提供有限的保证,因为我们增量迭代的集合可能会在迭代过程中发生变化.
请注意,SCAN、SSCAN、HSCAN和ZSCAN 的工作方式非常相似,因此本文档涵盖了所有四个命令。然而,一个明显的区别是,在SSCAN、HSCAN和ZSCAN的情况下,第一个参数是保存 Set、Hash 或 Sorted Set 值的键的名称。SCAN命令不需要任何键名参数,因为它迭代当前数据库中的键,所以迭代的对象就是数据库本身。
SCAN基本用法
SCAN 是一个基于游标的迭代器。这意味着在每次调用命令时,服务器都会返回一个更新的游标,用户需要在下一次调用中将其用作游标参数。
当游标设置为 0 时开始迭代,并在服务器返回的游标为 0 时终止。以下是 SCAN 迭代的示例:
redis 127.0.0.1:6379> scan 0
1) "17"
2) 1) "key:12"
2) "key:8"
3) "key:4"
4) "key:14"
5) "key:16"
6) "key:17"
7) "key:15"
8) "key:10"
9) "key:3"
10) "key:7"
11) "key:1"
redis 127.0.0.1:6379> scan 17
1) "0"
2) 1) "key:5"
2) "key:18"
3) "key:0"
4) "key:2"
5) "key:19"
6) "key:13"
7) "key:6"
8) "key:9"
9) "key:11"
在上面的示例中,第一次调用使用零作为游标来开始迭代。第二次调用使用前一次调用返回的游标作为回复的第一个元素,即 17。
如您所见,SCAN 返回值是一个包含两个值的数组:第一个值是下次调用中要使用的新游标,第二个值是一个元素数组。
由于在第二次调用中返回的游标为 0,因此服务器向调用者发出了迭代完成的信号,并且集合已被完全探索。以游标值为 0 开始迭代,并调用SCAN直到返回的游标再次为 0 称为完全迭代。
扫描保证
SCAN命令和SCAN系列中的其他命令能够为用户提供一组与完整迭代相关的保证。
- 完整迭代始终检索从完整迭代的开始到结束存在于集合中的所有元素。这意味着如果给定元素在迭代开始时在集合内,并且在迭代终止时仍然存在,那么SCAN在某个时候将其返回给用户。
- 从开始到结束,完整迭代永远不会返回集合中不存在的任何元素。因此,如果一个元素在迭代开始之前被删除,并且在迭代持续的所有时间内都不会添加回集合中,那么SCAN将确保永远不会返回该元素。
然而,由于SCAN关联的状态非常少(只是光标),它有以下缺点:
- 一个给定的元素可能会被多次返回。由应用程序来处理重复元素的情况,例如仅使用返回的元素以执行多次重新应用时安全的操作。
- 在完整迭代期间未始终存在于集合中的元素可能会被返回或不被返回:它是未定义的。
每次 SCAN 调用返回的元素数
SCAN系列函数不保证每次调用返回的元素数量在给定范围内。这些命令也允许返回零元素,只要返回的游标不为零,客户端就不应认为迭代完成。
但是返回的元素个数是合理的,即在实际迭代一个大集合时,SCAN可能返回最大元素个数几十个元素,也可能一次返回集合的所有元素当迭代集合足够小以在内部表示为编码数据结构时调用(这发生在小集合、散列和排序集合中)。
但是,用户可以使用COUNT选项调整每次调用返回的元素数量的数量级。
计数选项
虽然SCAN不保证每次迭代返回的元素数量,但可以使用COUNT选项凭经验调整SCAN的行为。基本上,用户使用 **COUNT **指定每次调用时应完成的工作量,以便从集合中检索元素。这只是实现的一个提示,但一般来说,这是您在大多数情况下可以从实现中得到的。
- 默认 COUNT 值为 10。
- 当迭代键空间,或者一个足够大的可以用哈希表表示的 Set、Hash 或 Sorted Set 时,假设没有使用MATCH选项,服务器通常会在每次调用时返回count或多于count个元素。请查看本文档后面的为什么 SCAN 可能会一次返回所有元素部分。
- 当迭代编码为整数集(仅由整数组成的小集)或编码为 ziplist 的散列和排序集(小散列和由小的单个值组成的集)时,通常在第一次SCAN调用中返回所有元素,而不管 COUNT价值。
重要提示:每次迭代都不需要使用相同的 COUNT 值。调用者可以根据需要自由地将计数从一次迭代更改为另一次迭代,只要在下一次调用中传递的游标是在上一次调用命令中获得的游标。
匹配选项
可以只迭代匹配给定 glob 样式模式的元素,类似于将模式作为唯一参数的KEYS命令的行为。
为此,只需在SCANMATCH
这是使用MATCH的迭代示例:
redis 127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood
(integer) 6
redis 127.0.0.1:6379> sscan myset 0 match f*
1) "0"
2) 1) "foo"
2) "feelsgood"
3) "foobar"
redis 127.0.0.1:6379>
重要的是要注意MATCH过滤器是在从集合中检索到元素之后应用的,就在将数据返回给客户端之前。这意味着如果模式匹配集合中的极少元素,则SCAN在大多数迭代中可能不会返回任何元素。一个例子如下所示:
redis 127.0.0.1:6379> scan 0 MATCH *11*
1) "288"
2) 1) "key:911"
redis 127.0.0.1:6379> scan 288 MATCH *11*
1) "224"
2) (empty list or set)
redis 127.0.0.1:6379> scan 224 MATCH *11*
1) "80"
2) (empty list or set)
redis 127.0.0.1:6379> scan 80 MATCH *11*
1) "176"
2) (empty list or set)
redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000
1) "0"
2) 1) "key:611"
2) "key:711"
3) "key:118"
4) "key:117"
5) "key:311"
6) "key:112"
7) "key:111"
8) "key:110"
9) "key:113"
10) "key:211"
11) "key:411"
12) "key:115"
13) "key:116"
14) "key:114"
15) "key:119"
16) "key:811"
17) "key:511"
18) "key:11"
redis 127.0.0.1:6379>
如您所见,大多数调用返回零元素,但最后一次调用使用 COUNT 为 1000 以强制命令对该迭代进行更多扫描。
类型选项
您可以使用该TYPE选项要求SCAN仅返回与给定 匹配的对象type,从而允许您遍历数据库以查找特定类型的键。TYPE选项仅在整个数据库SCAN上可用,而不是HSCAN或ZSCAN等。
该参数与TYPE命令返回type的字符串名称相同。请注意一个怪癖,其中某些 Redis 类型(例如 GeoHash、HyperLogLogs、Bitmaps 和 Bitfields)可能在内部使用其他 Redis 类型(例如字符串或 zset)实现,因此无法通过SCAN与相同类型的其他键区分开来. 例如,一个 ZSET 和 GEOHASH:
redis 127.0.0.1:6379> GEOADD geokey 0 0 value
(integer) 1
redis 127.0.0.1:6379> ZADD zkey 1000 value
(integer) 1
redis 127.0.0.1:6379> TYPE geokey
zset
redis 127.0.0.1:6379> TYPE zkey
zset
redis 127.0.0.1:6379> SCAN 0 TYPE zset
1) "0"
2) 1) "geokey"
2) "zkey"
需要注意的是,在从数据库中检索到元素之后也会应用TYPE过滤器,因此该选项不会减少服务器完成完整迭代所需的工作量,并且对于稀有类型,您可能不会收到任何元素在多次迭代中。
多个并行迭代
无限数量的客户端可能同时迭代同一个集合,因为迭代器的完整状态在游标中,每次调用都会获取并返回给客户端。根本没有服务器端状态。
在中间终止迭代
由于没有状态服务器端,但光标捕获了完整状态,调用者可以自由地中途终止迭代,而无需以任何方式向服务器发出信号。可以开始无数次迭代,并且永远不会终止而不会出现任何问题。
使用损坏的游标调用 SCAN
使用损坏的、否定的、超出范围的或其他无效的游标调用SCAN将导致未定义的行为,但绝不会导致崩溃。未定义的是, SCAN实现不再能确保关于返回元素的保证。
要使用的唯一有效游标是:
- 开始迭代时的光标值为 0。
- 上一次调用 SCAN 返回的光标以继续迭代。
终止保证
只有当迭代集合的大小保持在给定的最大大小范围内时, SCAN算法才保证终止,否则迭代一个总是增长的集合可能导致SCAN永远不会终止完整的迭代。
这很容易直观地看出:如果集合增长,为了访问所有可能的元素,需要做越来越多的工作,并且终止迭代的能力取决于对SCAN的调用次数及其 COUNT 选项值与集合增长的速度。
为什么 SCAN 可以在一次调用中返回聚合数据类型的所有项目?
在COUNT选项文档中,我们声明有时这一系列命令可能会在一次调用中一次返回 Set、Hash 或 Sorted Set 的所有元素,而不管COUNT选项值如何。发生这种情况的原因是基于游标的迭代器可以实现,并且只有当我们正在扫描的聚合数据类型表示为哈希表时才有用。然而,Redis 使用内存优化,其中小型聚合数据类型,直到它们达到给定数量的项目或给定的单个元素的最大大小,使用紧凑的单分配打包编码表示。在这种情况下,扫描没有要返回的有意义的游标,并且必须一次迭代整个数据结构,因此它唯一合理的行为是在调用中返回所有内容。
然而,一旦数据结构更大并被提升为使用真正的哈希表,SCAN系列命令将诉诸正常行为。请注意,由于返回所有元素的这种特殊行为仅适用于小型聚合,因此它对命令复杂性或延迟没有影响。然而,转换为真实哈希表的确切限制是用户可配置的,因此您可以在单个调用中看到返回的最大元素数取决于聚合数据类型可以有多大并且仍然使用打包表示。
另请注意,此行为特定于SSCAN、HSCAN和ZSCAN。SCAN本身从不显示这种行为,因为键空间始终由哈希表表示。
返回值
SCAN、SSCAN、HSCAN和ZSCAN返回两个元素的多批量回复,其中第一个元素是表示无符号 64 位数字(光标)的字符串,第二个元素是具有元素数组的多批量。
- SCAN元素数组是一个键列表。
- SSCAN元素数组是一个 Set 成员列表。
- HSCAN元素数组包含两个元素,一个字段和一个值,用于哈希的每个返回元素。
- ZSCAN元素数组包含两个元素,一个成员及其关联的分数,用于排序集的每个返回元素。
其他示例
哈希值的迭代。
redis 127.0.0.1:6379> hmset hash name Jack age 33
OK
redis 127.0.0.1:6379> hscan hash 0
1) "0"
2) 1) "name"
2) "Jack"
3) "age"
4) "33"
历史
- Redis 版本 >= 6.0.0:添加了
TYPE
子命令。
SORT
从 1.0.0 开始可用。
时间复杂度: O(N+M*log(M)) 其中 N 是列表或要排序的集合中的元素数,M 是返回元素的数量。当元素未排序时,复杂度为 O(N)。
返回或存储列表、集合或 排序集合中包含的元素key。
此命令还有SORT_RO只读变体。
默认情况下,排序是数字的,元素通过它们的值进行比较,解释为双精度浮点数。这是最简单形式的SORT :
SORT mylist
假设mylist是一个数字列表,此命令将返回相同的列表,其中元素从小到大排序。为了将数字从大到小排序,请使用DESC修饰符:
SORT mylist DESC
当mylist包含字符串值并且您想按字典顺序对它们进行排序时,请使用ALPHA修饰符:
SORT mylist ALPHA
!LC_COLLATE假设您正确设置了环境变量,Redis 支持 UTF-8 。
可以使用LIMIT修饰符限制返回元素的数量。此修饰符接受offset参数,指定要跳过的元素数和count参数,指定从 开始返回的元素数offset。以下示例将返回 的排序版本的 10 个元素mylist,从元素 0 开始(offset从零开始):
SORT mylist LIMIT 0 10
几乎所有修饰符都可以一起使用。以下示例将返回前 5 个元素,按字典顺序降序排列:
SORT mylist LIMIT 0 5 ALPHA DESC
按外部键排序
有时您希望使用外部键作为权重对元素进行排序,而不是比较列表、集合或排序集中的实际元素。假设列表mylist包含元素1,2并表示存储在和中的3对象的唯一 ID 。当这些对象具有存储在和 中的相关权重时,可以使用以下语句指示SORT使用这些权重进行排序:object_1object_2object_3weight_1weight_2weight_3mylist
SORT mylist BY weight_*
该选项采用用于生成用于排序的键BY的模式(在此示例中等于)。weight_这些键名是用列表中元素的实际值替换第一次出现的 (1,在本例2中3)。
跳过对元素进行排序
该BY选项还可以采用不存在的键,这会导致SORT跳过排序操作。GET如果您想在没有排序开销的情况下检索外部键(请参见下面的选项),这很有用。
SORT mylist BY nosort
检索外部密钥
我们之前的示例只返回排序后的 ID。object_1在某些情况下,获取实际对象而不是它们的 ID (object_2和)更有用object_3。根据列表、集合或排序集合中的元素检索外部键可以使用以下命令完成:
SORT mylist BY weight_* GET object_*
该GET选项可以多次使用,以便为原始列表、集合或排序集合的每个元素获取更多键。
GET元素本身也可以使用特殊模式#:
SORT mylist BY weight_* GET object_* GET #
存储 SORT 操作的结果
默认情况下,SORT将排序后的元素返回给客户端。使用该STORE选项,结果将作为列表存储在指定键处,而不是返回给客户端。
SORT mylist BY weight_* STORE resultkey
一个有趣的使用模式是将EXPIRESORT ... STORE超时与结果键相关联, 以便在SORT操作的结果可以缓存一段时间的应用程序中。其他客户端将使用缓存列表,而不是为每个请求调用SORT 。当密钥超时时,可以通过再次调用来创建缓存的更新版本。SORT ... STORE
请注意,为了正确实现此模式,重要的是要避免多个客户端同时重建缓存。这里需要某种锁定(例如使用SETNX)。
BY在和中使用散列GET
可以通过以下语法对哈希字段使用BY和选项:GET
SORT mylist BY weight_*->fieldname GET object_*->fieldname
该字符串->用于将键名与哈希字段名分开。如上所述,该键被替换,并访问存储在结果键中的散列以检索指定的散列字段。
*返回值
数组回复:在不传递store选项的情况下,该命令返回已排序元素的列表。 整数回复:store指定选项时,命令返回目标列表中已排序元素的数量。
SORT_RO
自 7.0.0 起可用。
时间复杂度: O(N+M*log(M)) 其中 N 是列表或要排序的集合中的元素数,M 是返回元素的数量。当元素未排序时,复杂度为 O(N)。
SORT命令的只读变体。它与原始SORT完全相同,但拒绝该STORE选项,并且可以安全地用于只读副本。
由于最初的SORT有一个STORE选项,因此它在技术上被标记为 Redis 命令表中的写入命令。因此,即使连接处于只读模式,Redis 集群中的只读副本也会将其重定向到主实例(请参阅 Redis 集群的READONLY命令)。
引入该SORT_RO变体是为了允许在只读副本中进行SORT行为,而不会破坏命令标志的兼容性。
有关详细信息,请参阅原始排序。
例子
SORT_RO mylist BY weight_*->fieldname GET object_*->fieldname
返回值
数组回复:已排序元素的列表。
TOUCH
自 3.2.1 起可用。
时间复杂度: O(N),其中 N 是要触摸的键的数量。
更改密钥的最后访问时间。如果键不存在,则忽略它。
返回值
整数回复:被触摸的键数。
例子
redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> TOUCH key1 key2
(integer) 2
redis>
TTL
从 1.0.0 开始可用。
时间复杂度: O(1)
返回具有超时的键的剩余生存时间。这种自省功能允许 Redis 客户端检查给定键将继续成为数据集的一部分的秒数。
在 Redis 2.6 或更早版本中,-1如果密钥不存在或密钥存在但没有关联的过期时间,则该命令返回。
从 Redis 2.8 开始,发生错误时的返回值发生了变化:
- -2如果密钥不存在,该命令将返回。
- -1如果密钥存在但没有关联的过期,则该命令返回。
另请参阅以毫秒分辨率返回相同信息的PTTL命令(仅在 Redis 2.6 或更高版本中可用)。
返回值
整数回复:以秒为单位的 TTL,或负值以指示错误(请参阅上面的描述)。
例子
redis> SET mykey "Hello"
"OK"
redis> EXPIRE mykey 10
(integer) 1
redis> TTL mykey
(integer) 10
redis>
历史
- Redis 版本 >= 2.8.0:添加了 -2 回复。
TYPE
从 1.0.0 开始可用。
时间复杂度: O(1)
返回存储在的值的类型的字符串表示形式key。可以返回的不同类型是:string、list、set、zset和 。hashstream
返回值
简单字符串回复:type of key,或nonewhenkey不存在。
例子
redis> SET key1 "value"
"OK"
redis> LPUSH key2 "value"
(integer) 1
redis> SADD key3 "value"
(integer) 1
redis> TYPE key1
"string"
redis> TYPE key2
"list"
redis> TYPE key3
"set"
redis>
UNLINK
从 4.0.0 开始可用。
时间复杂度:无论大小如何,每个键都被移除 O(1)。然后该命令在不同的线程中执行 O(N) 工作以回收内存,其中 N 是组成已删除对象的分配数。
此命令与DEL非常相似:它删除指定的键。就像DEL一样,如果一个键不存在,它就会被忽略。然而,该命令在不同的线程中执行实际的内存回收,因此它不是阻塞的,而DEL是。这就是命令名称的来源:该命令只是将键与键空间取消链接。实际的删除将在稍后异步发生。
返回值
整数回复:未链接的键数。
例子
redis> SET key1 "Hello"
"OK"
redis> SET key2 "World"
"OK"
redis> UNLINK key1 key2 key3
(integer) 2
redis>
WAIT
自 3.0.0 起可用。
时间复杂度: O(1)
此命令阻塞当前客户端,直到所有先前的写入命令都成功传输并至少被指定数量的副本确认。如果达到超时(以毫秒为单位),即使尚未达到指定数量的副本,该命令也会返回。
该命令将始终返回确认在WAIT命令之前发送的写入命令的副本数量,无论是在达到指定数量的副本的情况下,还是在达到超时的情况下。
几点说明:
- 当WAIT返回时,在当前连接的上下文中发送的所有先前的写命令都保证按照WAIT返回的副本数来接收。
- 如果命令作为MULTI事务的一部分发送,则该命令不会阻塞,而是尽快返回确认先前写入命令的副本数量。
- 超时 0 意味着永远阻塞。
- 由于WAIT返回在失败和成功的情况下达到的副本数量,客户端应该检查返回的值是否等于或大于它要求的复制级别。
一致性和等待
请注意,WAIT不会使 Redis 成为强一致性存储:虽然同步复制是复制状态机的一部分,但它并不是唯一需要的东西。然而,在 Sentinel 或 Redis 集群故障转移的上下文中,WAIT提高了现实世界的数据安全性。
具体来说,如果给定的写入转移到一个或多个副本,则更有可能(但不能保证)如果主服务器发生故障,我们将能够在故障转移期间提升接收到写入的副本:Sentinel 和Redis Cluster 将尽最大努力在可用副本集中提升最佳副本。
然而,这只是一个尽力而为的尝试,因此仍有可能丢失同步复制到多个副本的写入。
实施细节
由于引入了与副本的部分重新同步(PSYNC 功能),Redis 副本使用它们已经在复制流中处理的偏移量异步 ping 其 master。这以多种方式使用:
- 检测超时的副本。
- 断开连接后执行部分重新同步。
- 实施WAIT。
在实现WAIT的特定情况下,对于每个客户端,Redis 会记住在给定客户端的上下文中执行给定写入命令时生成的复制流的复制偏移量。当调用WAIT时,Redis 检查指定数量的副本是否已经确认了这个偏移量或更大的一个。
返回值
整数回复:该命令返回在当前连接的上下文中执行的所有写入所达到的副本数。
例子
> SET foo bar
OK
> WAIT 1 0
(integer) 1
> WAIT 2 1000
(integer) 1
在以下示例中,对WAIT的第一次调用不使用超时,并要求写入达到 1 个副本。它成功返回。在第二次尝试中,我们设置了一个超时,并要求将写入复制到两个副本。由于只有一个副本可用,等待一秒后解除阻塞并返回 1,副本数达到。