本文基于 Redis 官方文档,对 Redis Cluster 模式以及 Redis 术语进行了总结。有利于对 Redis 架构、功能和权衡有一个基本的了解。
1. 常用 Redis 术语
- 节点 (Node):一个单独的
redis-server
实例。在集群中,多个节点协同工作。 - 集群 (Cluster):一组 Redis 节点,它们自动在彼此之间对数据进行分区,提供高可用性和可伸缩性。
- 主节点 (Master 或 Primary):持有数据子集(分片)并为客户端请求提供服务的节点。它可以有一个或多个副本。
- 副本 (Replica 或 Secondary):维护主节点数据副本的节点。它不处理写请求,但可以处理读请求(取决于配置)。如果主节点失败,副本可以被提升为新的主节点。
- 哈希槽 (Hash Slot):Redis 集群中有 16384 个哈希槽。集群中的每个键都映射到这些槽中的一个。集群中的每个主节点负责这些槽的一个子集。
- Gossip 协议:节点之间用于相互通信的机制。它们交换有关集群状态、健康状况和配置的信息,从而实现自动发现和故障检测。
- 分片 (Sharding):将数据拆分到多个节点的过程。在 Redis 集群中,分片是通过在主节点之间分配 16384 个哈希槽来实现的。
2. Redis 集群如何工作
Redis 集群提供了一种运行 Redis 的方式,数据会自动在多个 Redis 节点之间进行分片。它提供了高度的可用性和可伸缩性,而无需依赖 Sentinel 或 ZooKeeper 等外部工具。
2.1 分片机制:哈希槽
Redis 集群分片的核心是哈希槽的概念。
- 整个键空间被划分为 16384 个槽。
- 为了确定一个键属于哪个槽,集群会计算该键的 CRC16 值并执行取模运算:
slot = CRC16(key) % 16384
。 - 集群中的每个主节点都被分配了一系列哈希槽。例如,在一个 3 节点的集群中:
- 节点 A 可能持有槽
0
到5500
。 - 节点 B 可能持有槽
5501
到11000
。 - 节点 C 可能持有槽
11001
到16383
。
- 节点 A 可能持有槽
当客户端想要对一个键执行操作时,它必须将命令发送到负责该键所在槽的节点。集群感知的客户端可以缓存槽到节点的映射,但如果集群拓扑发生变化(例如,在故障转移或重新分片后),客户端将收到一个 MOVED
重定向错误,告知它现在哪个节点持有该槽。
哈希标签 (Hash Tags):为了确保多个键存储在同一个槽中(用于像事务这样的多键操作),您可以使用哈希标签。如果一个键包含 {...}
模式,只有花括号内的字符串会用于计算哈希槽。例如,user:{1000}:name
和 user:{1000}:email
将映射到同一个槽。
2.2 高可用性与故障转移
高可用性是通过主从(master-replica)设置实现的。
- 每个主节点可以有一个或多个副本节点。
- 主节点会异步地将其所有数据复制到其副本。
- 节点之间使用 gossip 协议 持续通信,以监控彼此的健康状况。
- 如果一个主节点在可配置的时间内变得不可达,集群将启动故障转移。
- 剩余的主节点会投票选举一个失败主节点的副本,以提升为新的主节点。通常会选择拥有最新数据的副本。
- 一旦被提升,新的主节点将接管失败主节点的哈希槽并开始接受写请求。旧的主节点如果恢复,将作为新主节点的副本重新加入集群。
3. Redis Cluster 的优势
- 水平扩展性:您可以轻松地向集群中添加或删除节点,以扩展读写吞吐量和整体数据集大小。重新平衡哈希槽(重新分片)的过程可以在不停机的情况下实时进行。
- 高可用性:自动故障转移机制确保即使主节点发生故障,集群也能以最小的中断保持运行。
- 无单点故障:去中心化、无领导者的设计(用于集群管理)意味着没有单个组件的故障会导致整个系统瘫痪。
- 强大的性能:对于不严重依赖跨槽操作的工作负载,性能会随着主节点数量的增加而线性扩展。
4. 缺点与限制
- 客户端复杂性:客户端必须是“集群感知”的。它们需要处理
MOVED
和ASK
重定向,并维护集群的槽分布图。大多数现代 Redis 客户端都支持这一点,但与单机实例相比,这增加了一层复杂性。 - 多键操作:涉及多个键的操作仅在所有键都属于同一个哈希槽时才被支持。像
MSET
、MGET
和事务 (MULTI
/EXEC
) 这样的命令不能在映射到不同节点的键上执行。使用哈希标签是主要的解决方法。 - 数据倾斜:如果少数几个键(例如,使用相同的哈希标签)变得非常大或接收到不成比例的流量,它们可能会产生一个“热点”,因为它们无法被拆分到多个节点上。
- 管理开销:虽然比旧的设置更具自给自足性,但管理 Redis 集群(例如,添加节点、重新分片、调试)本质上比管理单个 Redis 实例更复杂。
- 有限的数据库支持:Redis 集群仅支持数据库 0。不允许使用
SELECT
命令。