前面我们介绍了哨兵原理及部署,哨兵解决的是 Redis 高可用,今天我们来介绍类似 MongoDB 的分片集群的 Redis 集群。Redis 集群是 Redis 官方提供的分布式解决方案,它通过 数据分片(Sharding) 和 主从复制(Replication) 来实现高可用性和横向扩展。
一、核心设计目标
- 高性能与线性扩展: 将数据分散到多个节点,理论上节点越多,集群总容量和吞吐量越高。
- 高可用性: 通过主从复制,在部分节点故障时,集群能继续提供服务。
- 可接受程度的写入安全: 主要依赖异步复制,在特定窗口期内可能丢失写入(与主从模式类似)。
- 无中心化架构: 客户端可以连接任意节点,节点间通过 Gossip 协议通信,共同构成一个去中心化的整体。
二、核心原理详解
1. 数据分片与哈希槽
这是 Redis 集群最核心的机制。
- 哈希槽: Redis 集群将整个数据空间划分为 16384 个槽。每个键值对都属于这 16384 个槽中的一个。
- 分片逻辑:
- 当客户端存储一个键时,集群会使用 CRC16 算法 对键名进行计算:
CRC16(key) % 16384。
- 计算结果决定了这个键属于哪个哈希槽。
- 每个 Redis 集群节点负责处理其中一部分哈希槽(比如节点 A 负责槽 0-5000,节点 B 负责 5001-10000 等)。
- 优势:
- 解耦数据与节点: 数据只与槽有关,而不是直接绑定到某个节点。这使得集群可以很容易地添加、删除节点,或者调整节点负责的槽范围,而无需移动所有数据。
- 管理单元: 槽是集群数据迁移和平衡的基本单位。
2. 节点角色与通信
- 主节点: 负责处理客户端请求(读写),并存储其所负责槽的数据。
- 从节点: 是主节点的副本,通过异步复制同步主节点的数据。其主要目的是在主节点故障时,通过选举升级为主节点,实现高可用。
- 通信协议:
- 节点间通过 Gossip 协议 进行通信。
- 每个节点定期(每秒多次)随机选择几个节点发送 PING 消息,接收方回复 PONG。通过这种方式,所有节点最终都能感知到其他节点的状态(在线、疑似下线、已下线)。
- 通信内容包含:节点状态、负责的哈希槽信息、集群配置纪元等。
3. 请求路由
客户端如何知道某个键在哪个节点上?有两种模式:
- 重定向模式:
- 智能客户端: 成熟的 Redis 客户端(如 Lettuce、Jedis)会缓存槽-节点映射,首次请求可能重定向,后续请求直接命中正确节点。
- 客户端向任意节点(例如节点 A)发送命令。
- 节点 A 计算该键所属的槽。
- 如果该槽由节点 A 负责,则直接执行命令并返回结果。
- 如果该槽由节点 B 负责,则节点 A 向客户端返回一个 MOVED 错误,并附带正确的节点地址(例如
MOVED 3999 192.168.1.2:6381)。
- 客户端收到 MOVED 错误后,更新本地缓存的槽-节点映射表,然后重新向正确的节点 B 发送命令。
- ASK 重定向: 发生在集群正在迁移槽的过程中。
- 如果请求的键不在当前节点,且该节点知道这个键正在迁移到另一个节点,它会返回 ASK 重定向。
- 客户端会向新节点发送一个 ASKING 命令,然后再次发送原命令。ASK 重定向是一次性的,不会更新客户端本地的槽映射缓存。
4. 高可用与故障转移
这是通过主从复制和 Raft 思想共识来实现的。
- 主观下线与客观下线:
- 主观下线: 节点 A 在
cluster-node-timeout 时间内未收到节点 B 的 PONG 回复,则节点 A 将节点 B 标记为“疑似下线”。
- 客观下线: 当集群中超过半数的主节点都将某个主节点 X 标记为“疑似下线”时,则节点 X 被标记为 客观下线。
- 故障转移:
- 当主节点被客观下线后,其从节点会发起故障转移流程。
- 从节点发现自己复制的主节点已下线,会向集群广播消息,请求其他主节点为自己投票。
- 其他主节点收到请求后进行投票(每个主节点在同一个配置纪元内只有一票)。
- 获得超过半数主节点投票的从节点将赢得选举,升级为新的主节点。
- 新主节点会接管原主节点负责的所有哈希槽,并广播消息通知整个集群,更新配置。
5. 数据迁移与重新分片
使用 redis-cli --cluster reshard 命令可以安全地将哈希槽从一个节点迁移到另一个节点。
- 迁移过程是在线进行的,集群无需下线。
- 迁移的基本单位是槽,但实际迁移会以槽中的键为单位逐步进行。
- 迁移过程中,对于正在迁移的槽:
- 源节点: 如果请求的键已被迁移,则返回 ASK 重定向。
- 目标节点: 会先处理所有带有 ASKING 标识的请求,直到迁移完成。
- 迁移完成后,目标节点正式成为该槽的新负责人,并通知整个集群更新映射关系。
三、重要特性与限制
特性
- 最终一致性: 主从异步复制,读从节点可能读到旧数据。
- 批量操作支持: 所有涉及多个键的命令(如
MSET, MGET),必须确保所有键位于同一个节点(即属于同一个哈希槽)。可以使用“哈希标签”来强制将不同的键分配到同一个槽。
限制(与单机 Redis 不同)
- 仅支持数据库 0: 集群模式不再支持
SELECT 命令选择多个数据库。
- 键事务限制: 所有键必须在同一个节点上才能使用事务(通过哈希标签实现)。
- 不支持多键命令: 除非所有键都在同一个哈希槽,否则无法使用
INTER, SUNION 等涉及多个键的命令。
- Lua 脚本限制: 脚本中使用的所有键也必须位于同一个节点。
架构示意图
+-------------------------------------+
| Redis Cluster |
| (Logical 16384 Slots) |
+-----+-----------+-----------+-------+
| | |
+-------+-----+ +---+----+ +----+------+
| Master 1 | |Master 2| | Master 3 |
| (Slots 0-5k)| |(5k-10k)| |(10k-16383)|
+-------+-----+ +---+----+ +----+------+
| | |
+-------+-----+ +---+----+ +----+------+
| Slave 1 | | Slave 2| | Slave 3 | (Replicas)
+-------------+ +--------+ +-----------+
客户端可以连接任意节点。
节点间通过Gossip协议(PING/PONG)通信。
希望这篇关于 Redis Cluster 原理的解析能帮助你更好地理解这一核心的分布式系统方案。如果你对更多数据库或中间件技术感兴趣,欢迎在 云栈社区 交流探讨。
|