【Redis】数据分片机制和集群机制

发布于:2025-08-28 ⋅ 阅读:(13) ⋅ 点赞:(0)

【一】Redis Cluster 核心设计目标与原理​

Redis Cluster 是 Redis 官方提供的分布式数据库解决方案,其核心设计目标是在不需要中间件代理的情况下,实现:
(1)​高性能与线性扩展​:通过分片(Sharding)将数据分布到多个节点,允许水平扩展,处理更多数据和更高并发。
(2)​高可用性​:通过主从复制和自动故障转移,保证服务在部分节点失败时仍然可用。
(3)​可接受程度的可用性​:遵循 CAP 理论,在网络分区(Split-brain)发生时,优先保证数据一致性(C)​​ 和分区容错性(P)​,可能会牺牲部分可用性(A)。

​核心原理​:Redis Cluster 采用去中心化(Decentralized)​​ 的架构。每个节点都保存了整个集群的状态信息(元数据),并通过 ​Gossip 协议​ 与其他节点通信,维护集群状态。客户端可以直接与任意节点连接,节点会告知客户端正确的数据位置。

【二】数据分片机制 (Sharding)​​

这是 Redis Cluster 的核心,它决定了数据如何分布到不同的节点上。

【1】哈希槽 (Hash Slot)​​

Redis Cluster 没有使用传统的一致性哈希,而是引入了 ​哈希槽 (Hash Slot)​​ 的概念。
(1)​数量固定​:一个 Redis Cluster 包含 ​16384​ (2^14) 个哈希槽。
(2)​逻辑单元​:哈希槽是数据管理和迁移的基本单位。集群中的每个键都属于这 16384 个槽中的一个。
(3)​计算方式​:通过 CRC16 算法计算键的哈希值,然后对 16384 取模,来确定该键属于哪个槽。
slot = CRC16(key) % 16384

【2】槽的分配​

(1)分配主节点

当集群创建时,这 16384 个槽会被分配给集群中的主节点(Master Nodes)​。

(2)例如,一个包含 3 个主节点的集群:

Node A: 负责槽 0 - 5500
Node B: 负责槽 5501 - 11000
Node C: 负责槽 11001 - 16383

每个主节点负责的槽数量可以不同,以此实现权重分配,让性能更强的节点承担更多数据。

(3)键哈希标签 (Hash Tags)​​

1-​问题​:默认情况下,多个键可能被散列到不同的节点上,无法保证它们在同一节点。但有些操作(如 MSET、MGET)或事务需要原子性地在多个键上执行,这就要求这些键必须在同一个节点上。
2-解决方案​:​哈希标签 {}。
计算槽位时,只计算 {和 }之间的字符串的哈希值。
例如,键 user:{1000}.profile和 user:{1000}.account,只会计算 1000的哈希值。因此它们会被分配到同一个槽,从而存储在同一个节点上。

​(4)客户端与服务器的交互 (重定向机制)​​

客户端可以连接集群中的任意节点。
(1)​命中​:如果客户端访问的键所在的槽正好由当前连接的节点负责,则节点直接处理命令。
(2)​重定向 (MOVED)​​:如果键所在的槽不由当前节点负责,节点会向客户端回复一个 ​MOVED错误,并附上该槽所在的正确节点的 IP 和端口。
1-MOVED 3999 192.168.1.20:6379-> “键在槽 3999,它由 192.168.1.20:6379 负责”
2-智能客户端​:成熟的 Redis 客户端库会缓存 槽 -> 节点的映射关系。在收到 MOVED错误后,它会更新本地缓存,并自动重定向到正确的节点执行命令。对应用层是透明的。
(3)​迁移中重定向 (ASKING)​​:在集群进行槽重分配(Resharding)​​ 时,一个槽可能正在从节点 A 迁移到节点 B。如果客户端访问节点 A 请求一个已经迁走的键,节点 A 会回复 ​ASK错误,引导客户端去临时访问节点 B。客户端需要先向节点 B 发送 ASKING命令,然后再执行原命令。这是一个临时重定向。

【三】redis集群Cluster节点故障转移与选举机制​

【1】节点角色与心跳​

(1)主节点 (Master)​​:负责存储数据、处理命令。
(2)从节点 (Slave)​​:是主节点的副本,通过异步复制同步主节点的数据。​其主要作用是在主节点故障时进行替换,实现故障转移,平时不处理读请求(但可以通过 READONLY命令开启读,分担主节点压力)。
(3)Gossip 协议​:所有节点都通过 ​PING/PONG​ 消息持续通信。这些消息包含了自身和其他节点的状态信息(如是否下线、负责的槽等)。

【2】主观下线 (PFAIL) 与客观下线 (FAIL)​​

故障发现分为两步:
(1)​主观下线 (PFAIL - Possibly Failed)​​
1-节点 A 在超过 cluster-node-timeout时间后仍未收到节点 B 的 PONG 响应。
2-节点 A 会在本地将节点 B 标记为 PFAIL状态。
3-此时只是节点 A主观认为节点 B 可能下线了,可能是因为网络抖动。
(2)​客观下线 (FAIL)​​
1-节点 A 通过 Gossip 消息询问集群中的其他节点对节点 B 的看法。
2-如果集群中超过半数的主节点都认为节点 B 处于 PFAIL状态(即也联系不上节点 B),那么节点 A 就会将节点 B 的状态升级为 ​FAIL(客观下线)​。
3-一旦被标记为 FAIL,整个集群就会一致认为该节点已真正下线,并开始触发故障转移流程。

【3】故障转移选举 (基于Raft的变种)​​

当主节点被标记为 FAIL后,其下属的从节点会发起选举,竞选成为新的主节点。选举过程如下:
(1)​资格检查​:从节点会检查其主节点的故障时间是否足够长,以确保有足够的时间来传播故障信息。
(2)延迟选举​:从节点会等待一个随机的、短暂的延迟时间(0.5 * cluster-node-timeout),然后再开始选举。这有助于避免多个从节点同时发起投票。
(3)发起投票​:
符合资格的从节点会向集群中所有其他主节点广播一条 ​CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST​ 消息,请求投票。
(4)投票条件​:一个主节点只会给第一个收到请求的从节点投一票,并且必须满足以下所有条件:
1-它的主节点已被标记为 FAIL状态。
2-该主节点负责的槽没有被其他节点接管(防止重复选举)。
3-这个主节点在当前配置纪元(currentEpoch)​还没有投过票。
4-请求的从节点的主节点确实是这个下线的主节点。
(5)赢得选举​:如果一个从节点收集到了超过半数的主节点的投票,它就赢得选举。
(6)晋升为主​:赢得选举的从节点会执行以下操作:
1-给自己分配其旧主负责的所有哈希槽。
2-向整个集群广播一条 ​PONG​ 消息,告知其他节点自己已成为新的主节点,并负责这些槽。
3-开始处理原本由旧主负责的请求。

【3】配置纪元 (Epoch)​​:

(1)这是一个单调递增的计数器,充当集群的“逻辑时钟”。
(2)每次选举和槽分配等重大事件都会伴随 epoch 的递增。
(3)它用于区分新旧决策。例如,一个带有更高 epoch 的节点信息会覆盖旧的、epoch 值低的信息,从而解决网络分区恢复后的状态冲突问题。

【四】Redis 哨兵模式(Sentinel)的选举过程

哨兵模式是 Redis 实现高可用性(High Availability)​​ 的核心方案,其核心目标是:在主节点故障时,能自动将一个从节点提升为新的主节点,并让整个集群感知到这个变化,从而继续提供服务。

【1】核心概念与角色​

(1)​主节点 (Master)​​:负责处理写请求和读请求的数据节点。
(2)从节点 (Slave)​​:主节点的复制品,通过复制同步主节点的数据。故障转移的候选者。
(3)哨兵节点 (Sentinel)​​:一个独立的、特殊的 Redis 进程。它不存储数据,它的核心任务是监控、通知、自动故障转移和配置提供。哨兵本身也是一个分布式系统,通常由 ​3个或以上奇数个​ 哨兵节点组成集群,以实现自身的高可用和决策的可靠性。

【2】选举过程的详细步骤​

哨兵的故障转移选举不是一个单一动作,而是一个包含故障发现、决策、选举新主、故障转移的完整流程。

(1)​阶段一:主观下线 (Subjective Down, SDOWN) -> 发现故障​

(1)过程​:
1.每个哨兵节点会以每秒一次的频率向所有它监控的主节点、从节点以及其他哨兵节点发送 PING命令。
2.如果一台实例(例如主节点)在配置的 down-after-milliseconds时间(如 30秒)内没有有效回复 PONG,那么单个哨兵就会在本地将该实例标记为 ​​“主观下线”​。

(2)特点​:
主观判断​:这只是某个哨兵自己的看法。可能是因为网络抖动、主节点自身压力大等原因,并不代表主节点真的挂了。

(2)阶段二:客观下线 (Objective Down, ODOWN) -> 确认故障​

(1)过程​:
1.当一个哨兵将主节点标记为主观下线后,它会通过 ​SENTINEL is-master-down-by-addr​ 命令询问其他哨兵节点,是否也认为该主节点不可用。
2.其他哨兵会回复自己对该主节点的判断结果。
3.如果超过法定数量(Quorum)​​ 的哨兵(包括自己)都报告主节点主观下线,那么发起询问的哨兵就会将主节点的状态升级为 ​​“客观下线”​。

(2)​Quorum(法定人数)​​:
1-这是在哨兵配置中设定的一个关键值(sentinel monitor )。
2-它不是指需要进行故障转移的哨兵数量,而是确认一个节点客观下线所需的最小票数。
3-例如,配置 quorum 2意味着至少需要 2 个哨兵认为主节点下线,才能判定为客观下线。

​至此,集群达成共识:主节点确实挂了,需要启动故障转移流程。​​

(3)阶段三:哨兵领导者选举 (Sentinel Leader Election) -> 由谁执行转移?​​

​这是最核心的选举过程。​​ 既然决定要故障转移,那么由哪个哨兵来负责执行这个操作呢?如果多个哨兵同时发起故障转移,会导致混乱。

Redis 哨兵使用了 ​Raft 算法的变种来选举一个领导者哨兵(Leader Sentinel)​。
(1)触发条件​:任何一个哨兵确认主节点为客观下线后,都有资格发起领导者选举。
(2)拉票请求​:这个哨兵会将自己的当前配置纪元(Configuration Epoch)​​(一个单调递增的计数器)加 1,然后向其他哨兵广播一条消息,请求它们投票给自己。
(3)投票规则​:每个哨兵在一个配置纪元内,​对第一个收到的拉票请求投赞成票,并且只能投一次。
(4)​赢得选举​:发起选举的哨兵如果收集到了超过半数的赞成票(>= N/2 + 1,例如 3 个哨兵需要 2票,5个需要3票),它就成为领导者。
(5)选举失败​:如果在规定时间内没有哨兵获得多数票,那么选举会超时。哨兵会等待一个随机时间后,用新的、递增的配置纪元重新发起选举,直到成功选出领导者为止。
​注意​:Quorum 用于确认故障,而多数派(超过半数)​​ 用于选举领导者。这是两个不同的概念。

(4)阶段四:新主节点选举 (Promoting a New Master) -> 选举谁当新主?​​

领导者哨兵被选举出来后,它并不自己成为主节点,而是负责从旧的从节点中选出一个最适合的,并将其提升为新的主节点。筛选规则按优先级顺序如下:
(1)健康状态​:排除主观下线和断线的从节点。
(2)​优先级​:比较 slave-priority配置值(默认100),​优先级数值越小,优先级越高。
(3)复制偏移量​:如果优先级相同,选择复制偏移量(Replication Offset)最大的从节点。这意味着它拥有最完整的数据。
(4)运行ID​:如果以上都相同,选择运行ID(Run ID)最小的从节点(一个字典序的随机字符串,作为最终仲裁)。

领导者哨兵根据以上规则选出最佳从节点后,会向其发送 SLAVEOF no one命令,使其停止复制,转变为主节点。

(5)阶段五:故障转移与通知​

(1)提升新主​:领导者哨兵向选出的新主节点发送 SLAVEOF no one命令,使其晋升。
(2)切换从节点​:领导者哨兵通过发布/订阅功能向其他从节点发送新的配置信息,让它们转而复制新的主节点。
(3)​旧主降级​:如果旧主节点恢复,领导者哨兵会向其发送 SLAVEOF命令,让其成为新主的从节点。
(4)更新配置​:领导者哨兵会将这个新的系统配置(新的主节点地址)广播给所有客户端和其他哨兵。客户端连接到哨兵可以获取到最新的主节点信息。

【3】设计精髓与注意事项:​​

(1)​分布式共识​:哨兵模式的核心是分布式系统下的共识问题。它通过 Quorum 和 Raft 算法,在没有中心节点的情况下,高效、可靠地达成一致决策,避免了“脑裂”(Split-brain)问题。
(2)哨兵数量​:​必须部署至少 3 个哨兵节点,且最好分布在不同的物理机器上。因为:
1-领导者选举需要超过半数的同意。
2-1个哨兵:自己挂了整个HA系统就失效。
3-2个哨兵:如果其中一个挂了,剩下的1个无法达到“超过半数”(2/2=1,需要 >1)的条件,无法选举领导者,导致故障转移失败。
(3)客户端集成​:客户端需要支持哨兵协议,能够连接哨兵来查询当前的主节点地址。常见的客户端库(如 Lettuce、Jedis)都提供了Sentinel支持。
(4)异步复制与数据丢失​:由于主从复制是异步的,在故障转移时,如果旧主节点有部分数据还未同步到新主节点,这部分数据就会丢失。