一文搞懂 Redis 集群 (Redis Cluster)


一文搞懂 Redis 集群 (Redis Cluster)

Redis,作为当今最流行的内存数据结构存储系统之一,以其高性能、丰富的数据结构和原子操作等特性,在缓存、消息队列、排行榜、分布式锁等众多场景中得到了广泛应用。然而,随着业务量的增长和数据规模的扩大,单机 Redis 实例往往会遇到瓶颈:

  1. 内存容量限制: 单个 Redis 实例的内存容量受限于服务器物理内存,当数据量超过单机内存上限时,无法继续存储。
  2. 并发处理能力限制: Redis 的主要工作线程是单线程的(虽然 I/O 和部分后台任务是多线程的),在高并发场景下,单个实例的 QPS 存在上限。
  3. 可用性问题: 单机 Redis 存在单点故障风险,一旦该实例宕机,整个服务将不可用。

为了解决这些问题,Redis 官方在 3.0 版本推出了 Redis Cluster,这是一个原生的、分布式的、高可用的解决方案。本文将深入探讨 Redis Cluster 的方方面面,助你彻底搞懂它。

一、 为什么需要 Redis Cluster?—— 单机 Redis 的痛点

在深入了解 Redis Cluster 之前,我们先回顾一下单机 Redis 面临的主要挑战,这也正是 Redis Cluster 要解决的核心问题:

  • 数据量剧增,内存不够用: 业务发展迅速,需要缓存或存储的数据越来越多,单台服务器的内存往往捉襟见肘。即使使用 RDB 或 AOF 持久化,数据最终还是要加载到内存中才能提供服务。
  • 并发量提升,CPU 成瓶颈: Redis 的单线程模型虽然避免了多线程上下文切换的开销,但在 CPU 密集型操作或极高的并发请求下,单核 CPU 会成为性能瓶颈。
  • 服务高可用,单点故障无法容忍: 对于核心业务,系统需要 7x24 小时稳定运行。单机 Redis 一旦发生故障(硬件损坏、进程崩溃、网络中断等),将导致相关服务中断,影响用户体验甚至造成经济损失。

虽然在 Redis Cluster 出现之前,社区也有一些解决方案,如客户端分片、代理层分片(如 Twemproxy, Codis)以及基于主从复制和 Sentinel 的高可用方案,但它们各有优劣:

  • 客户端分片: 逻辑分散在各个客户端,难以统一管理,升级维护复杂。
  • 代理层分片: 引入了额外的代理层,增加了系统复杂度和潜在的性能瓶颈,代理本身也可能成为单点。
  • Sentinel + 主从: 主要解决高可用问题,但无法解决数据分片和内存/CPU 扩展问题,所有数据仍然存储在一个 Master 节点上。

Redis Cluster 的出现,旨在提供一个 官方的、内置的、无需中心节点或代理的 集群解决方案,同时解决 数据分片(水平扩展)高可用(故障转移) 两大核心问题。

二、 Redis Cluster 核心概念解析

理解 Redis Cluster 的工作原理,首先要掌握其几个核心概念:

1. 数据分片 (Data Sharding) 与哈希槽 (Slot)

为了将数据分散到不同的节点上,Redis Cluster 引入了 哈希槽 (Hash Slot) 的概念。整个集群预设了 16384 (0 ~ 16383) 个哈希槽。

  • Key 与 Slot 的映射: 当客户端需要操作某个 Key 时,Redis Cluster 会使用 CRC16 算法 计算该 Key 的校验和,然后对 16384 取模,得到一个 0 到 16383 之间的整数,这个整数就是该 Key 所属的哈希槽。
    HASH_SLOT = CRC16(key) mod 16384
  • Slot 与节点的分配: 集群中的每个 主节点 (Master Node) 负责处理一部分哈希槽。例如,一个包含 3 个主节点的集群,可能会这样分配:

    • 节点 A 负责槽 0 ~ 5460
    • 节点 B 负责槽 5461 ~ 10922
    • 节点 C 负责槽 10923 ~ 16383

    这种 槽位->节点 的映射关系存储在每个节点上,并且通过 Gossip 协议在集群内部同步。客户端连接集群中的任意节点,都能获取到完整的槽位映射信息。

  • 哈希标签 (Hash Tags): Redis Cluster 规定,如果 Key 中包含 {} 并且 {} 中有内容,那么计算哈希槽时只会使用 {} 内的部分。例如,{user:1000}:name{user:1000}:age 这两个 Key,计算 Slot 时都只会使用 user:1000 这部分,因此它们会被分配到同一个哈希槽。这对于需要进行多 Key 操作(如 MGET, MSET, 事务, Lua 脚本)的场景非常重要,因为 Redis Cluster 的多 Key 操作要求所有 Key 必须位于同一个槽中。

2. 节点 (Node) 与集群总线 (Cluster Bus)

  • 节点角色: Redis Cluster 中的节点分为 主节点 (Master)从节点 (Slave)。主节点负责处理读写请求和维护自己负责的哈希槽数据;从节点主要用于复制对应主节点的数据,并在主节点宕机时参与选举,尝试成为新的主节点,实现故障转移。
  • P2P 通信: Redis Cluster 是一个 去中心化 的架构,节点之间通过 Gossip 协议 进行 P2P 通信,交换状态信息(节点存活状态、槽位分配信息、配置变更等)。
  • 集群总线 (Cluster Bus): 每个 Redis Cluster 节点除了监听用于客户端连接的端口(如 6379)外,还会额外监听一个 集群总线端口,端口号通常是客户端端口号 加 10000(如 16379)。节点之间通过这个总线端口使用二进制协议进行通信,交换 Gossip 消息、心跳包、故障检测信息等。这个总线是集群能够自我管理和维护的关键。

3. 主从复制 (Master-Slave Replication)

Redis Cluster 内部的主从复制机制与单机模式下的主从复制类似。每个主节点可以拥有一个或多个从节点。

  • 数据冗余: 从节点复制主节点的数据,提供数据备份。
  • 故障转移基础: 当主节点发生故障时,其从节点可以被选举为新的主节点,接管原来的哈希槽,保证服务的连续性。
  • 读扩展(有限): 默认情况下,Redis Cluster 会将读请求也路由到负责该槽的主节点。但客户端可以通过发送 READONLY 命令连接到从节点,进行读操作,以分担主节点的读压力。但需要注意数据一致性问题(从节点数据可能略有延迟)。

4. Gossip 协议

Gossip 协议是一种 P2P 的、最终一致性的信息传播协议。在 Redis Cluster 中,它用于:

  • 节点发现: 新节点加入集群时,通过 Gossip 协议与其他节点建立联系。
  • 状态传播: 节点之间互相交换各自知道的集群状态信息,如哪些节点存活、哪些节点疑似下线、哈希槽的分配情况等。通过不断交换信息,最终整个集群的所有节点都会拥有相似的集群视图(可能存在短暂的不一致)。
  • 故障检测: 节点之间会定期发送 PING 包,如果某个节点在一定时间内没有收到另一个节点的 PONG 响应,就会将其标记为 疑似下线 (PFAIL - Possible Fail)。当集群中 超过半数 的主节点都将某个节点标记为 PFAIL 时,该节点会被标记为 客观下线 (FAIL),并触发后续的故障转移流程。

Gossip 协议的优点是去中心化、容错性好,即使部分节点通信暂时中断,信息最终也能通过其他节点传播。缺点是信息传播有延迟,集群状态的收敛需要一定时间。

5. 重定向 (Redirection - MOVED 与 ASK)

由于客户端可能连接到集群中的任意节点,而这个节点不一定是负责处理目标 Key 所在哈希槽的节点,因此 Redis Cluster 设计了重定向机制:

  • MOVED 重定向: 当客户端向一个节点发送命令,但该命令所操作的 Key 对应的哈希槽 并不由该节点负责 时,该节点会返回一个 MOVED 错误,并携带目标槽位以及负责该槽位的正确节点的 IP 和端口。
    GET mykey
    -MOVED 12345 192.168.1.100:6380

    智能客户端 (Cluster-aware Client) 在收到 MOVED 错误后,会 更新自己内部缓存的槽位映射关系,然后自动将命令 重新发送 到正确的节点。后续对该槽的操作会直接发送到新节点。这是一个 永久性 的重定向(直到下次集群拓扑变更)。

  • ASK 重定向: ASK 重定向发生在 哈希槽迁移 (Resharding) 的过程中。当一个槽正在从节点 A 迁移到节点 B 时:

    • 如果客户端请求的 Key 对应的槽仍在节点 A,但在迁移计划中,节点 A 会检查这个 Key 是否实际存在于本地。
      • 如果 Key 存在于节点 A,则正常处理。
      • 如果 Key 不存在于节点 A(可能已迁移到 B,或者本来就不存在),节点 A 会返回一个 ASK 错误,指向正在接收该槽的节点 B。
        GET migratingkey
        -ASK 12345 192.168.1.101:6381
    • 客户端收到 ASK 错误后,不会更新本地的槽位映射。它需要先向目标节点 B 发送一个 ASKING 命令,表明下一个命令是由于 ASK 重定向而来的。然后,再将原始命令发送给节点 B。
    • 节点 B 收到 ASKING 命令后,会为这个连接设置一个一次性标志,允许执行来自一个正在导入的槽的命令。执行完下一个命令后,该标志自动清除。

    ASK 重定向是 临时性 的,只在槽迁移期间发生,用于引导客户端在迁移未完成时找到可能已经迁移过去的数据。

6. 故障转移 (Failover)

高可用是 Redis Cluster 的核心特性之一。当一个主节点被标记为客观下线 (FAIL) 后,其下属的从节点会发起故障转移流程:

  • 资格检查: 只有与故障主节点断线时间未超过阈值(cluster-node-timeout * cluster-slave-validity-factor)的从节点才有资格参与选举。
  • 选举延迟: 为了让数据更完整(复制偏移量更大)的从节点更有机会胜出,从节点会根据自己的复制偏移量计算一个延迟时间,偏移量越大,延迟越短,越早发起选举。
  • 发起选举: 延迟结束后,从节点向集群中的其他主节点发送 CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST 请求投票。
  • 投票: 主节点在一定时间窗口内只会给第一个请求投票的、符合资格的从节点投票。只有获得 超过半数 主节点投票的从节点才能胜选。
  • 替换主节点: 胜选的从节点执行 SLAVEOF no one 命令,提升自己为主节点,接管原故障主节点负责的所有哈希槽,并向集群广播自己的新状态。

整个故障转移过程是自动进行的,无需人工干预,保证了集群的可用性。

三、 Redis Cluster 架构概览

Redis Cluster 采用 无中心节点的对等网络 (Peer-to-Peer) 架构。

  • 节点互联: 所有节点(无论主从)都通过集群总线互相连接,形成一个 网状结构 (Mesh)
  • 数据分布: 数据根据 Key 的哈希槽值分布在不同的主节点上。
  • 高可用保障: 每个主节点至少有一个从节点作为备份,并通过内部的故障检测和自动故障转移机制保障服务连续性。
  • 客户端交互: 客户端需要使用支持 Redis Cluster 协议的 智能客户端。客户端内部维护一份 槽位 -> 节点 的映射缓存。当发送命令时,客户端计算 Key 的槽位,直接将命令发送到对应的节点。如果收到 MOVEDASK 重定向,客户端能自动处理并更新映射缓存。

这种架构避免了单点瓶颈和代理层的复杂性,具有良好的可扩展性和容错性。

四、 Redis Cluster 如何工作?(客户端视角)

  1. 连接与初始化: 客户端启动时,需要配置集群中 至少一个 节点的地址。客户端会连接到这个(或这些)节点,并通过 CLUSTER NODESCLUSTER SLOTS 命令获取 完整的集群拓扑信息和槽位映射关系,缓存在本地内存中。
  2. 命令执行:
    • 客户端计算要操作的 Key 所属的哈希槽。
    • 根据本地缓存的槽位映射,找到负责该槽的主节点。
    • 将命令直接发送给该主节点。
    • 接收并处理响应。
  3. 处理重定向:
    • 如果收到 MOVED 响应,说明本地缓存的槽位映射已过期。客户端会更新缓存,并将命令 重新发送MOVED 指向的新节点。
    • 如果收到 ASK 响应,说明 Key 所在的槽正在迁移。客户端 不会更新 缓存,而是先向 ASK 指向的目标节点发送 ASKING 命令,然后再将原始命令发送给该目标节点。
  4. 集群状态维护: 智能客户端会持续关注集群状态变化。例如,当某个节点不可达或收到 MOVED 时,客户端可能会触发重新获取集群拓扑信息的操作,以保持本地映射的准确性。

可见,智能客户端 在 Redis Cluster 中扮演了非常重要的角色,它屏蔽了集群内部的复杂性(如路由、重定向),让开发者可以像使用单机 Redis 一样操作集群。常用的 Redis 客户端库(如 Jedis, Lettuce, redis-py 等)都提供了对 Redis Cluster 的支持。

五、 Redis Cluster 的优点

  • 水平扩展能力 (Scalability): 可以通过增加主节点来线性扩展集群的内存容量和处理能力。数据自动分片到新节点。
  • 高可用性 (High Availability): 基于主从复制和自动故障转移机制,当主节点宕机时,能自动选举从节点接替,服务中断时间很短。
  • 分布式存储 (Data Distribution): 数据自动分散到多个节点,降低了单节点的负载和内存压力。
  • 去中心化架构 (Decentralized): 无需中心节点或代理服务器,节点之间对等通信,部署和维护相对简单,避免了中心节点的瓶颈和单点故障。
  • 官方支持 (Official Support): 作为 Redis 官方提供的集群方案,有持续的维护和更新保障。

六、 Redis Cluster 的缺点与限制

  • 多键操作受限 (Multi-key Operations Limitation): 涉及多个 Key 的原子操作(如 MSET, MGET, DEL, 事务, Lua 脚本)要求所有 Key 必须位于 同一个哈希槽 中。需要通过 哈希标签 (Hash Tags) {...} 来确保相关 Key 落在同一槽位,这在一定程度上增加了开发复杂性。
  • 事务支持有限 (Limited Transaction Support): 事务只能在单个节点内执行,无法实现跨节点的分布式事务。
  • 数据迁移开销 (Resharding Overhead): 在增加或移除节点,或者重新平衡槽位分配(Resharding)时,需要迁移大量数据,这会消耗网络带宽和节点 CPU 资源,可能对在线服务产生一定影响。迁移过程中 ASK 重定向也会轻微增加延迟。
  • Gossip 协议开销: 节点间频繁的 Gossip 通信会消耗一定的网络带宽和 CPU 资源,尤其在集群规模较大时。
  • 客户端兼容性要求 (Client Compatibility): 必须使用支持 Redis Cluster 协议的客户端。老旧的或不支持集群协议的客户端无法直接与 Redis Cluster 交互。
  • 至少需要 3 个主节点才能保证高可用: 为了在发生网络分区或节点故障时能够可靠地进行故障检测和选举(需要超过半数主节点参与),官方推荐生产环境至少部署 3 个主节点。加上从节点,最小的健壮集群通常需要 6 个节点(3 主 3 从)。

七、 部署与运维考量

  • 配置: 启用 Redis Cluster 需要在每个节点的 redis.conf 文件中设置 cluster-enabled yes。还需要配置 cluster-config-file (存储集群状态的文件),cluster-node-timeout (节点超时时间) 等参数。
  • 集群创建: 可以使用 Redis 5.0 及以后版本自带的 redis-cli --cluster create host1:port1 ... hostN:portN --cluster-replicas <N> 命令来快速创建和配置集群(包括槽位分配和主从关系设置)。在早期版本中,通常使用 redis-trib.rb 脚本(Ruby 编写)。
  • 集群管理: 可以通过 redis-cli -c (c 表示 cluster mode) 连接到集群,并使用 CLUSTER INFO, CLUSTER NODES, CLUSTER SLOTS 等命令查看集群状态。添加/删除节点、重新分片等操作也可以通过 redis-cli --cluster 相关子命令完成。
  • 监控: 需要监控集群中每个节点的健康状况、内存使用、网络流量、命令延迟,以及集群整体的槽位分布、故障转移事件等。

八、 Redis Cluster vs. Sentinel

经常有人会将 Redis Cluster 与 Redis Sentinel 进行比较。它们解决的问题有所不同:

  • Redis Sentinel: 主要目标是 高可用。它监控一组 主从复制 的 Redis 实例,在主节点宕机时自动进行故障转移,选举新的主节点。但 Sentinel 本身不负责数据分片,所有数据仍然存储在一个 Redis 主实例上。它解决了单点故障问题,但没有解决单机容量和性能瓶颈问题。
  • Redis Cluster: 同时解决了 高可用数据分片(水平扩展) 的问题。它将数据分散到多个主节点上,每个主节点可以有从节点备份,并具备自动故障转移能力。

选择依据:

  • 如果你的数据量和并发量不大,单机 Redis 能够承载,但需要保证服务的高可用性,那么 Redis Sentinel + 主从复制 是一个更简单、资源消耗更少的选择。
  • 如果你的数据量巨大,或者并发压力很高,单机 Redis 无法满足需求,需要进行水平扩展,同时还需要高可用保障,那么 Redis Cluster 是官方推荐的、更全面的解决方案。

九、 总结

Redis Cluster 是 Redis 官方提供的强大武器,用于构建大规模、高可用的 Redis 服务。它通过 哈希槽 机制实现了数据的 自动分片,解决了单机 Redis 的容量和性能瓶颈;通过 主从复制 和基于 Gossip 协议自动故障检测与转移 机制,保障了服务的高可用性。其 去中心化 的架构设计使得集群具有良好的 可扩展性容错性

当然,Redis Cluster 也并非银弹,它带来了更高的复杂性,尤其是在多键操作和事务方面有所限制,并且对客户端有特定要求。理解其核心概念,如哈希槽、Gossip 协议、节点通信、重定向(MOVED/ASK)和故障转移流程,是有效使用和运维 Redis Cluster 的关键。

希望通过本文的详细介绍,你已经对 Redis Cluster 有了全面而深入的理解,能够根据自身的业务需求,做出明智的技术选型和应用。


THE END