*多键操作 (Multi-key operations)

在 Redis 中,多键(Multi-key)操作允许您在单个命令中同时处理多个键。然而,这些命令的具体行为和限制取决于您的 Redis 架构配置(如单机版、高可用集群或分布式分片集群)。

根据不同的 Redis 配置,多键命令通常表现出以下三种行为之一: - 单槽(single-slot):命令操作的所有键必须映射到同一个哈希槽(hash slot)中。 - 跨槽/全分片(cross-slot, all shards):命令可以跨集群中的所有分片(shards)并发执行。 - 跨槽/单分片内(cross-slot, within a single shard):命令可以跨越不同的哈希槽,但这些槽必须位于同一个物理分片(节点)内。


*读写命令的行为差异

根据 Redis 的部署形态及集群 API 的开启状态,多键命令的行为表现如下:

  1. 禁用集群(单机或主从架构,无分片)
    • 所有的多键操作都可以在整个数据库(单个分片)上无限制地安全执行。
  2. 启用集群且开启 OSS Cluster API(标准 Redis 集群)
    • 绝大多数涉及多个键的复杂命令(如集合交并差、事务等)要求所有键必须位于当前的同一个哈希槽(Single-slot)内。如果键分散在不同槽中,将触发 CROSSSLOT 错误。
  3. 启用高级集群/代理模式(禁用 OSS Cluster API)
    • 部分托管服务或代理层(如 Redis Enterprise / Redis Cloud 的特定配置)能够在上层对某些多键命令进行聚合,从而允许其跨越所有分片或在单分片内跨槽执行。

*管道、事务与脚本

*1. 管道(Pipelines)

在单机 Redis 实例中,管道操作可以对任意键执行。但在集群环境中,管道中的各个命令如果包含多键操作,依然需要遵循分片与槽位的限制。

# 管道示例(在单机实例中对任意键均有效)
PIPELINE
SET user:1 "Alice"
SET product:100 "Widget"
GET user:1
GET product:100
EXEC

*2. 事务(Transactions)

在使用 MULTI/EXEC 代码块时:

  • 非集群环境:可以对任意键执行事务操作。
  • 集群环境:事务块(MULTI/EXEC)内涉及的所有命令,其操作的键必须路由到同一个哈希槽
# 事务示例
MULTI
SET counter:a 1
SET counter:b 2
INCR counter:a
INCR counter:b
EXEC

注意:在标准 Redis 集群中,如果 counter:acounter:b 属于不同的哈希槽,上述事务在集群环境下将无法执行。

*3. Lua 脚本与 Redis 函数(Lua Scripts & Functions)

所有通过 EVALEVALSHA 执行的 Lua 脚本,或者 Redis Functions,其涉及的所有键必须明确作为参数(KEYS 数组)传递,并且这些键必须全部映射到同一个哈希槽中。在脚本内部动态拼接或隐式访问不属于该槽位的键会导致未定义行为或引发错误。


*常见的多键命令限制归类

*1. 必须在同一槽位(Single-slot)执行的命令

这些命令通常涉及复杂的跨键计算,要求原子性,因此在集群中要求所有键必须 hash 到同一个槽位:

*2. 允许跨槽(Cross-slot)执行的特定命令

在标准 Redis 集群中,有一些基础的多键命令已被扩展,能够支持跨槽或跨分片操作(具体取决于客户端或代理的路由机制):


*常见错误信息

在集群环境下错误地使用多键操作,通常会遇到以下错误:

  • CROSSSLOT Keys in request don't hash to the same slot:请求中的键未散列到同一个哈希槽。
  • MOVED:键当前所在的槽已迁移到其他节点(常见于集群扩缩容/重新分片期间)。
  • TRYAGAIN:由于槽位数据正在迁移中,操作暂时不可用,请稍后重试。

*最佳解决方案:哈希标签(Hash Tags)

为了在分布式或集群环境下依然能高效执行多键操作,Redis 引入了 哈希标签(Hash Tags) 机制。

*原理

如果键名中包含 {...} 符号,Redis 在计算哈希槽时,只会对花括号 {} 内部的字符串进行哈希计算。这样可以强制让一组相关联但名称不同的键存储在同一个哈希槽(即同一个分片)中。

*示例

  • user:{1000}:profileuser:{1000}:orders 的哈希槽均基于 1000 进行计算,因此它们必定位于同一个哈希槽
  • 您可以安全地在它们之间执行 MULTI/EXEC 事务、Lua 脚本或复合的多键命令。

*规则细节

  • 必须包含 { 且其右侧必须有 }
  • {} 之间必须至少有一个字符。
  • 如果存在多个 {},以第一个有效的花括号对为准。

*性能与架构考量

  1. 单槽操作性能最高:由于不需要跨节点或跨槽的内部协调 and 路由,单槽多键操作的性能与单机模式一致。
  2. 避免大范围跨槽操作:跨分片的多键操作(如未加标签的 MGET)需要客户端或中间件进行命令拆分、多节点并发请求以及结果合并,这会显著增加网络延迟和 CPU 开销。
  3. 高版本优化(Redis 8+): 在 Redis 8 及以上版本中,如果 KEYSSCAN 命令的 glob 匹配模式中包含了不带通配符的精确哈希标签(例如 SCAN 0 MATCH {abc}*),引擎会自动将其优化为仅扫描对应的一个哈希槽,而不再盲目扫描全库,从而使这些命令在生产环境中具备了极高的实用性和安全边界。