redis cluster原理分析
1. 概述
Redis Cluster是Redis的分布式解决方案,旨在实现数据分片和高可用性。它通过将数据分布在多个节点上,每个节点负责一部分哈希槽(Hash Slot),从而支持水平扩展。同时,通过主从复制和自动故障转移机制,确保在节点故障时系统仍能正常运行。
2. 数据分片机制
2.1 哈希槽(Hash Slot)
- Redis Cluster将整个键空间划分为
CLUSTER_SLOTS个哈希槽,即16384个。 - 每个键根据其名称通过CRC16算法计算出一个哈希值,然后对16384取模,确定其所属的哈希槽。
- 每个主节点(Master Node)负责管理一组哈希槽。
- 在源码中,
clusterNode结构体中的slots数组用于标记该节点负责的槽位:
unsigned char slots[CLUSTER_SLOTS/8]; /* slots handled by this node */
2.2 键到槽的映射
- 映射函数
keyHashSlot(key)实现了从键名到槽号的转换。 - 这种设计允许集群在节点间动态迁移槽位,而无需重新哈希所有数据,仅需迁移特定槽位的数据。
3. 节点通信与发现
3.1 集群总线(Cluster Bus)
- 所有集群节点之间通过端口偏移量(默认为客户端端口+10000)建立TCP连接,形成一个内部的二进制协议通信通道,称为“集群总线”。
- 集群总线使用Gossip协议来传播消息,确保集群状态的最终一致性。
3.2 Gossip协议
- 消息类型:节点间交换PING、PONG、MEET等消息,携带自身状态和已知节点信息。
- 成员发现:新节点通过
CLUSTER MEET命令加入集群,接收方会向其发送自己的节点列表,实现自动发现。 - 状态传播:节点定期向其他节点发送PING,并接收PONG,以检测节点健康状况。
- 源码中定义了多种消息类型:
#define CLUSTERMSG_TYPE_PING 0 /* Ping */
#define CLUSTERMSG_TYPE_PONG 1 /* Pong (reply to Ping) */
#define CLUSTERMSG_TYPE_MEET 2 /* Meet "let's join" message */
4. 故障检测与转移
4.1 故障检测
- 主观下线(PFAIL - Possibly Fail):当一个节点在一段时间内(由
node timeout配置)无法收到另一个节点的PONG回复时,会将其标记为主观下线。 - 客观下线(FAIL):当一个节点认为某个主节点主观下线后,会向其他主节点请求确认。如果超过半数的主节点也认为该节点下线,则达成共识,将其标记为客观下线。这需要
quorum个节点的同意。 clusterNode结构体中的flags字段记录了节点的状态:
int flags; /* CLUSTER_NODE_... */
#define CLUSTER_NODE_PFAIL 4 /* Failure? Need acknowledge */
#define CLUSTER_NODE_FAIL 8 /* The node is believed to be malfunctioning */
4.2 故障转移(Failover)
当一个主节点被标记为客观下线时,其从节点(Slave Node)会发起故障转移,选举自己成为新的主节点。
4.2.1 选举过程
- 资格检查:从节点首先检查自己是否有资格参与选举。例如,它必须与旧主节点保持足够的同步,避免数据丢失过多。
- 请求投票:符合条件的从节点会向所有主节点发送
FAILOVER_AUTH_REQUEST消息,请求投票。 - 投票决策:每个主节点在一轮选举中只会投一票,通常会投给第一个请求且满足条件的从节点。
- 赢得选举:如果从节点获得的票数超过半数(
quorum),则选举成功,开始故障转移。
4.2.2 源码分析
clusterHandleSlaveFailover函数是处理从节点故障转移的核心逻辑。failover_auth_sent标志位防止一个从节点重复发起投票请求。failover_auth_count用于统计收到的选票数量。
5. 高可用性工作过程
5.1 主从复制
- 从节点持续复制主节点的数据,保证数据冗余。
- 当主节点故障时,从节点可以接管服务,确保服务不中断。
5.2 自动故障转移流程
- 检测:集群中的多数节点确认主节点故障(客观下线)。
- 选举:最合适的从节点(通常是复制偏移量最大的)通过上述选举过程成为新的主节点。
- 更新配置:新主节点更新其
configEpoch(配置纪元),这是一个单调递增的版本号,用于解决脑裂问题。它会向其他节点广播UPDATE消息,通知自己的新角色和槽位所有权。 - 重定向客户端:其他节点和客户端收到
MOVED重定向错误,将后续请求发送到新的主节点。
5.3 配置纪元(Config Epoch)
configEpoch是解决冲突的关键机制。当两个节点对同一槽的所有权发生争执时,拥有更高configEpoch的节点获胜。- 这确保了即使在网络分区的情况下,也能选出唯一的权威节点,防止数据不一致。
clusterNode结构体中包含此字段:
uint64_t configEpoch; /* Last configEpoch observed for this node */
6. 设计原因
- 去中心化:没有单点故障,所有节点地位平等,通过Gossip协议达成共识。
- 高性能:客户端可以直接连接到负责其所需键的节点,减少代理层的开销。
- 可扩展性:通过增加节点并迁移槽位,可以轻松地进行水平扩展。
- 最终一致性:采用最终一致性模型,而非强一致性,以换取更高的可用性和分区容忍性,符合CAP理论。
- 简单性:相比外部的一致性协调服务(如ZooKeeper),Redis Cluster的设计相对简洁,易于部署和维护。