在使用 Redis 管道技术时,要注意一些限制,避免踩坑:
Pipeline 不能保证原子性 - Pipeline 只是将客户端发送命令的方式改为批量发送,而服务端在接收到 Pipeline 发来的命令后,将其拆解为一条条命令,然后依然是串行执行。执行过程中,服务端有可能执行其他客户端的命令,所以无法保证原子性。如需保证原子性,可以考虑使用事务或 Lua 脚本。
Pipeline 不支持回滚 - Pipeline 没有事务的特性,如果待执行命令的前后存在依赖关系,请勿使用 Pipeline。
Pipeline 命令不宜过大 - 使用管道发送命令时,Redis Server 会将部分请求放到缓存队列中(占用内存),执行完毕后一次性发送结果。如果需要发送大量的命令,会占用大量的内存,因此应该按照合理数量分批次的处理。
Pipeline 不支持跨 slot 访问 - 由于 Pipeline 不支持跨 slot 访问,因此,在 Redis 集群模式下使用 Pipeline 时要确保访问的 key 都在同一 slot 中。
在 Redis 集群模式中,数据会被分布到不同的节点上,而这些节点又被划分为多个哈希槽(hash slot)。每个哈希槽都有对应的节点负责处理其中的数据。
当使用 Pipeline 时,如果涉及的命令访问的键不在同一个哈希槽中,就会出现跨 slot 访问的情况。而 Redis 的 Pipeline 不支持跨 slot 访问。
这意味着,在 Redis 集群模式下使用 Pipeline 时,需要确保访问的键都在同一 slot 中。也就是说,你要执行的这些命令所操作的键,必须被分配到同一个哈希槽对应的节点上,否则 Redis 会引发异常,提示“cross-slot keys in request don't hash to the same slot”。
为了满足这个要求,可能需要对要执行的命令进行规划和调整。例如,将涉及到不同哈希槽的命令拆分成多个 Pipeline 分别执行,或者确保在一个 Pipeline 中的命令所操作的键都位于同一个哈希槽内。这样可以避免出现跨 slot 访问的错误,保证 Pipeline 能够正常执行并提高性能。
在 Redis 集群模式下,跨 slot 访问数据可能会导致报错或无法正常执行操作。
Redis 集群采用虚拟槽分区算法,将数据分布到不同的节点上。每个节点负责处理一部分槽(slot),槽的取值范围是0到16383。当进行数据存取时,Redis 会根据特定算法计算键对应的槽,然后自动跳转到对应的节点上进行操作。
而 Redis 的 Pipeline 不支持跨 slot 访问,并且所有涉及到多个键的 Redis 指令,都要求这些键处于同一个 slot 中。如果试图在集群模式下进行跨 slot 操作,即使这些 slot 实际上在同一个节点上,也会报类似“cross-slot keys in request don't hash to the same slot”的错误。
禁止跨 slot 操作的原因主要包括:
性能考虑:允许跨槽操作需要在不同节点之间进行复杂的协调和网络通信,可能会显著降低操作的性能。Redis 设计为高性能的存储系统,这种限制有助于保持操作的速度和效率。
简化分布式环境下的操作:通过限制操作仅在相同槽的键上执行,简化了分布式环境下的数据管理,减少了数据一致性和同步问题的复杂度,使得集群管理更为简单。
提高可扩展性和可靠性:这种设计允许 Redis 集群在节点失败或网络分区发生时更容易地进行数据迁移和故障转移。如果允许跨槽操作,将增加数据迁移和恢复的复杂性,可能会影响到整个系统的可靠性。
分区的自治性:将数据划分到不同的槽中,并限制跨槽操作,有助于保证每个分区的自治性。每个节点可以独立处理其槽内的操作,从而减少了节点之间的依赖性。
若要在 Redis 集群中执行涉及多个键的操作,可以使用 Redis 提供的 hashtags 功能,通过在键中使用“{}”括起一部分关键信息,让相关键能被分配到同一个 slot 中。例如,“{rank:level}:1”和“{rank:level}:2”这两个键就会被分配到同一个 slot 中,因为计算哈希时只使用“{}”内的字符串“rank:level”。需注意,“{}”可以放在键的任意位置,且如果有多个“{}”,只有第一个“{}”生效。