命令键规范
命令键规范是什么,以及如何在客户端中使用它们
Redis 中的许多命令接受键名称作为输入参数。COMMAND
(和 COMMAND INFO
)响应中的第 9 个元素是一个数组,其中包含命令的键规范。
与 Redis 7.0 之前采用的第一个键、最后一个键和步长方案相比,键规范描述了从给定命令的参数中提取一个或多个键名称的规则。键规范提供了一种强大而灵活的机制。在引入这些规范之前,Redis 客户端没有简单的方法以编程方式提取所有命令的键名称。
支持集群的 Redis 客户端必须在诸如 EVAL
和 ZUNIONSTORE
(依赖于 numkeys 参数)或 SORT
及其许多子句等命令的情况下,将键的提取逻辑硬编码。或者,COMMAND GETKEYS
可用于实现类似的提取效果,但延迟较高。
Redis 客户端没有义务支持键规范。它可以继续使用旧版的 第一个键、最后一个键 和 步长 方案以及保持不变的 movablekeys 标志。
但是,实现键规范支持的 Redis 客户端可以合并其大部分键的提取逻辑。即使客户端遇到不熟悉的键规范类型,它始终可以恢复到 COMMAND GETKEYS
命令。
也就是说,大多数支持集群的客户端只需要一个键名称来执行正确的命令路由,因此,即使命令具有一个不熟悉的规范,客户端仍然可以使用其其他规范。
键规范是具有以下键的映射
- begin_search::键提取的起始索引。
- find_keys: 相对于 BS 识别键的规则。
- notes:如果有的话,有关此键规范的注释。
- flags:指示数据访问类型。
begin_search
规范的 begin_search 值告知客户端提取的开始。该值是一个映射。有三种类型的 begin_search
- index: 键名称参数从一个常量索引开始。
- keyword: 键名称在特定关键字(标记)之后开始。
- unknown: 一种未知类型的规范 - 有关更多详细信息,请参见 不完整标志部分。
index
begin_search
的 index 类型表示输入键出现在一个常量索引处。它是 spec 键下的一个映射,具有一个键
- index: 客户端应从中开始提取键名称的基于 0 的索引。
keyword
begin_search
的 keyword 类型表示一个文本标记位于键名称参数之前。它是 spec 下的一个映射,具有两个键
- keyword: 标记键名称参数开头的关键字(标记)。
- startfrom: 客户端应从中开始搜索的参数数组的索引。这可以是一个负值,这意味着搜索应从参数数组的末尾开始,按相反顺序进行。例如,-2 的含义是从倒数第二个参数开始反向搜索。
keyword 搜索类型的更多示例包括
SET
的begin_search
规范类型为 index,值为 1。XREAD
的begin_search
规范类型为 keyword,值分别为 "STREAMS" 和 1,分别作为 keyword 和 startfrom。MIGRATE
的 start_search 规范类型为 keyword,值为 "KEYS" 和 -2。
find_keys
键规范的 find_keys
值告诉客户端如何继续搜索键名。find_keys
有三种可能的类型
- range: 键在特定索引处或相对于最后一个参数停止。
- keynum: 一个附加参数指定输入键的数量。
- unknown: 一种未知类型的规范 - 有关更多详细信息,请参见 不完整标志部分。
range
find_keys
的 range 类型是在 spec 键下具有三个键的映射
- lastkey: 相对于
begin_search
的最后一个键参数的索引。这可以是一个负值,在这种情况下它不是相对的。例如,-1 表示继续提取键直到最后一个参数,-2 表示提取到倒数第二个,依此类推。 - keystep: 找到一个键后,应该跳过的参数数量,以找到下一个键。
- limit: 如果 lastkey 的值为 -1,我们使用 limit 通过一个因子停止搜索。0 和 1 表示没有限制。2 表示剩余参数的一半,3 表示三分之一,依此类推。
keynum
find_keys
的 keynum 类型是在 spec 键下具有三个键的映射
- keynumidx: 相对于
begin_search
的包含键数量的参数的索引。 - firstkey: 相对于
begin_search
的第一个键的索引。这通常是 keynumidx 之后的下一个参数,在这种情况下,它的值会大一。 - keystep: 找到一个键后,应该跳过的参数数量,以找到下一个键。
示例
SET
命令的 range 为 0、1 和 0。MSET
命令的 range 为 -1、2 和 0。XREAD
命令的 range 为 -1、1 和 2。ZUNION
命令有一个 start_search 类型为 index,值为 1,以及一个 find_keys 类型为 keynum,值为 0、1 和 1。AI.DAGRUN
命令有一个 start_search 类型为 keyword,值为 "LOAD" 和 1,以及一个 find_keys 类型为 keynum,值为 0、1 和 1。
注意:这不是一个完美的解决方案,因为模块编写者可以提出任何东西。但是,此机制应该允许提取绝大多数命令的关键名称参数。
注释
关于非显式键规范注意事项(如果适用)。
标志
键规范可以有其他标志,提供有关键的更多详细信息。这些标志分为三组,如下所述。
访问类型标志
以下标志声明命令用于访问键的值或其元数据的访问类型。键的元数据包括 LRU/LFU 计数器、类型和基数。这些标志与发送回客户端的回复无关。
每个键规范都精确地包含以下标志之一
- RW:读写标志。该命令修改存储在键的值或其元数据中的数据。此标志标记每个操作,该操作明显不是删除、覆盖或只读。
- RO:只读标志。该命令仅读取键的值(尽管它不一定返回该值)。
- OW:覆盖标志。该命令覆盖存储在键的值中的数据。
- RM:删除标志。该命令删除键。
逻辑操作标志
以下标志声明对存储为键的值及其 TTL(如果有)执行的操作类型,而不是元数据。这些标志描述了命令在数据上执行的逻辑操作,由输入参数驱动。这些标志与修改或返回元数据(例如键的类型、基数或存在)无关。
每个键规范可能包含以下标志
- access:访问标志。此标志表示命令返回、复制或以某种方式使用存储在键中的用户数据。
此外,规范可以精确地包含以下标志之一
- update:更新标志。该命令更新存储在键的值中的数据。新值可能取决于旧值。此标志标记每个操作,该操作明显不是插入或删除。
- insert:插入标志。该命令仅向值添加数据;不修改或删除现有数据。
- delete:删除标志。该命令明确地从存储在键中的值中删除数据。
其他标志
关键规范可能具有以下标志
- not_key: 此标志表示指定的参数不是键。在计算应将命令分配给 Redis 集群的哪个插槽时,此参数与键的处理方式相同。出于所有其他目的,此参数不应被视为键。
- incomplete: 此标志在下面解释。
- variable_flags: 此标志在下面解释。
incomplete
在指定键时,某些命令采用非常规方法,这使得提取变得困难。例如,考虑对 MIGRATE
的调用,其中包括文字字符串 "KEYS" 作为其 AUTH 子句的参数。我们的键规范会错过标记,并且提取将从错误的索引开始。
因此,我们认识到键规范不完整,并且可能无法提取所有键。但是,我们保证,即使是不完整的规范也绝不会产生错误的键名称,前提是命令在语法上正确。
在 MIGRATE
的情况下,搜索从末尾开始(startfrom 的值为 -1)。如果并且当我们遇到名为 "KEYS" 的键时,我们只会提取其后的键名称参数的子集。这就是为什么 MIGRATE
在其键规范中具有 incomplete 标志。
不完整性的另一个案例是 SORT
命令。在此,begin_search
和 find_keys
的类型为 unknown。客户端应恢复调用 COMMAND GETKEYS
命令以从参数中提取键名称,而不是本机实现它。例如,困难在于字符串 "STORE" 既是 SORT
的关键字(令牌),也是有效的文字参数。
注意: 具有 incomplete 键规范的唯一命令是 SORT
和 MIGRATE
。我们不希望将来添加此类命令。
variable_flags
在某些命令中,相同键名参数的标志可能会取决于其他参数。例如,考虑一下 SET
命令及其可选的 GET 参数。如果没有 GET 参数,SET
仅限写入,但有了它,它就会变成读写命令。当此标志存在时,这意味着键规范标志涵盖所有可能的选项,但有效标志取决于其他参数。
示例
SET
的键规范
1) 1) "flags"
2) 1) RW
2) access
3) update
3) "begin_search"
4) 1) "type"
2) "index"
3) "spec"
4) 1) "index"
2) (integer) 1
5) "find_keys"
6) 1) "type"
2) "range"
3) "spec"
4) 1) "lastkey"
2) (integer) 0
3) "keystep"
4) (integer) 1
5) "limit"
6) (integer) 0
ZUNION
的键规范
1) 1) "flags"
2) 1) RO
2) access
3) "begin_search"
4) 1) "type"
2) "index"
3) "spec"
4) 1) "index"
2) (integer) 1
5) "find_keys"
6) 1) "type"
2) "keynum"
3) "spec"
4) 1) "keynumidx"
2) (integer) 0
3) "firstkey"
4) (integer) 1
5) "keystep"
6) (integer) 1