redis如何保证可用性?
Redis 通过多种机制和架构来保证其高可用性,核心目标是确保服务在发生部分节点故障(如主节点宕机)时,仍能继续提供服务,并尽可能减少数据丢失。主要策略包括:
🧱 1. 主从复制 (Replication)
-
基本原理: 这是高可用性的基础。一个 Redis 实例作为主节点 (Master),负责处理写操作。一个或多个 Redis 实例作为从节点 (Slaves / Replicas),异步复制主节点的数据。
-
如何保证可用性:
-
数据冗余: 数据在多个节点上有副本。即使主节点宕机,从节点上仍有(可能稍旧)的数据副本。
-
读负载均衡: 客户端可以将读请求分发到从节点,减轻主节点压力,间接提升整体服务的稳定性(写请求仍必须发送到主节点)。
-
故障转移的基础: 主从结构是实现自动故障转移(由 Sentinel 或 Cluster 触发)的前提。
-
🔍 2. Redis Sentinel (哨兵)
-
基本原理: Sentinel 是一个独立的分布式系统,由一个或多个 Sentinel 进程组成。它不存储数据,而是专门用于监控 Redis 主从节点,并在主节点故障时自动执行故障转移。
-
核心功能:
-
监控 (Monitoring): 持续检查主节点和从节点是否正常运行。
-
通知 (Notification): 当被监控的 Redis 实例出现问题时,可以通过 API 或其他集成方式通知系统管理员或其他应用程序。
-
自动故障转移 (Automatic Failover): 这是 Sentinel 的核心价值。当 Sentinel 集群(需要多个 Sentinel 实例达成共识)判定主节点客观下线 (Objectively Down) 时,它会执行以下操作:
-
在存活的从节点中,根据配置规则(如优先级、复制偏移量)选举出一个新的主节点。
-
让其他从节点改为复制这个新的主节点。
-
通知客户端配置更新,客户端应连接新的主节点。
-
-
配置提供者 (Configuration Provider): 客户端可以向 Sentinel 查询当前的主节点地址。
-
-
如何保证可用性:
-
自动化故障转移: 主节点宕机后,能在较短时间内(秒级到分钟级,取决于配置)自动切换到一个从节点,恢复写服务,无需人工干预。
-
Sentinel 自身高可用: Sentinel 设计为分布式集群。即使个别 Sentinel 进程挂掉,只要集群中还有多数 (
quorum
) Sentinel 进程存活并能达成共识,就能正常工作。 -
避免脑裂: Sentinel 通过
quorum
和majority
机制(需要多个 Sentinel 确认主节点下线)来减少误判和脑裂发生的概率。
-
-
适用场景: 中小规模部署,需要自动故障转移但不需要大规模水平扩展的场景。是 Redis 早期推荐的高可用方案。
🌐 3. Redis Cluster (集群)
-
基本原理: Redis 内置的分布式数据分片和高可用方案。它将数据自动分片 (Sharding) 到多个节点(称为分片或槽位 Slot)上,每个分片由一个主节点和至少一个从节点组成。
-
核心功能:
-
数据分片: 数据按 key 的哈希值分布到
16384
个槽位中,槽位再分配到不同的主节点上。客户端可以直接将请求路由到正确的节点。 -
主从复制: 每个分片内部是主从结构,数据在主节点和其从节点间复制。
-
自动故障转移: 每个分片内部的高可用机制与 Sentinel 类似,但由集群本身管理。当某个主节点被集群中的大多数主节点判定为故障时,其对应的从节点会自动晋升为主节点。
-
节点间通信 (Gossip): 集群节点间通过 Gossip 协议交换状态信息,维护集群拓扑视图。
-
-
如何保证可用性:
-
节点级冗余: 每个分片有主从节点,主节点故障时从节点能接管。
-
服务连续性: 只要不是某个分片的主节点和其所有从节点同时挂掉(或者大多数主节点挂掉导致无法达成共识),集群就能继续提供服务。故障转移在分片内部自动完成。
-
无中心化: 没有单点故障(不像 Sentinel 需要独立的 Sentinel 进程,但 Cluster 自身的节点也承担管理功能)。
-
可扩展性: 支持水平扩展,通过增加分片来提升性能和容量,这也间接增强了整体系统的可用性。
-
-
适用场景: 大规模部署,需要同时满足高可用性、大容量和高性能需求的场景。是 Redis 官方推荐的现代高可用和扩展方案。
3. Redis Cluster (集群) 的数据分片是按照节点来分还是槽位slot来分的
这是一个非常好的问题!Redis Cluster 的数据分片机制的核心是 槽位 (Slot),节点 (Node) 是槽位的物理承载者。更准确地说:
-
数据分片的基本单位是槽位 (Slot):
-
Redis Cluster 将整个数据空间划分为 16384 (16K) 个固定的逻辑槽位 (Slot)。
-
每个有效的键 (Key) 通过一个哈希函数
CRC16(key) % 16384
计算出一个介于 0 到 16383 之间的值,这个值决定了这个键属于哪个槽位。 -
数据分片是按照 Key 映射到哪个槽位来决定的。 同一个槽位内的所有 Key 会被存储在一起。
-
-
节点 (Node) 负责管理槽位:
-
集群中的每个 主节点 (Master Node) 会被分配一个或多个槽位范围(例如:节点 A 负责槽位 0-5000,节点 B 负责槽位 5001-10000,节点 C 负责槽位 10001-16383)。
-
槽位到节点的映射关系 (Cluster Slots) 是整个集群状态的核心元数据。每个节点都维护一份完整的、最新的槽位分配信息。
-
客户端可以向集群中任意节点发送请求。如果请求的 Key 不属于该节点负责的槽位,节点会根据其存储的槽位映射信息,向客户端返回一个
MOVED
或ASK
重定向错误,告知客户端正确的节点地址。
-
总结关键点:
-
逻辑分片靠槽位: 数据空间被逻辑划分为 16384 个 Slot。Key 通过哈希计算固定归属到一个 Slot。
-
物理存储靠节点: 集群将这些 Slot 动态地分配给各个主节点来负责存储和管理。一个主节点管理一个或多个连续的 Slot 范围。
-
动态分配: Slot 到节点的映射关系不是固定的。可以通过集群管理命令 (
CLUSTER ADDSLOTS
,CLUSTER DELSLOTS
,CLUSTER SETSLOT
等) 动态地将 Slot 从一个节点迁移到另一个节点,这是 Redis Cluster 实现水平扩展(扩容/缩容)和负载均衡的基础。 -
高可用基础: 每个 Slot 的数据在主节点和其从节点之间复制。如果主节点故障,其负责的 Slot 会被提升的从节点接管,保证这些 Slot 的数据服务不中断。
为什么说“按 Slot 分”比“按节点分”更准确?
-
抽象层: Slot 提供了一个稳定的逻辑抽象层。客户端只需要知道 Key 属于哪个 Slot(通过固定的哈希计算),而不需要关心当前是哪个物理节点在负责这个 Slot。
-
灵活性: 数据迁移是以 Slot 为单位进行的。当需要增加节点(扩容)或减少节点(缩容)时,管理员或自动化工具可以将一组特定的 Slot 从源节点迁移到目标节点。这期间集群仍然可用(部分 Slot 可能处于迁移状态)。如果直接“按节点分”,迁移的粒度会非常大(整个节点的数据),操作更复杂且影响更大。
-
均衡性: 理论上,16384 个 Slot 可以非常均匀地分配给节点。即使节点数量不是 16384 的约数,通过合理分配 Slot 范围,也能实现较好的数据负载均衡。直接按节点分(比如简单的哈希取模节点数)在节点数量变化时会导致大量的数据重新分布(Resharding)。
简单来说:
-
问:数据存在哪里? 答:数据根据 Key 的哈希值存放在其对应的 Slot 里。
-
问:Slot 由谁管理? 答:Slot 由集群动态分配给具体的主节点(及其从节点)来管理存储和访问。
因此,Redis Cluster 的数据分片首先是按照槽位 (Slot) 进行逻辑划分,然后由节点 (Node) 负责物理存储和管理分配给它的槽位。Slot 是分片的核心抽象和操作单元。
3. Redis Cluster (集群):主从节点的判定、和主从复制的过程、故障自动转移的过程
Redis Cluster 的主从节点判定、复制过程以及故障自动转移机制是其高可用性的核心。下面详细解释这三个关键过程:
一、主从节点的判定
Redis Cluster 中的节点角色(主节点/从节点)并非预先固定,而是通过配置和集群状态动态确定的:
-
初始主节点 (Master):
-
当 Redis Cluster 初始化时(例如通过
redis-cli --cluster create
命令),所有初始加入的节点默认都是主节点。 -
每个主节点会被分配一个 槽位范围(Slot)(如
0-5460
)。拥有至少一个槽位的节点即为主节点。
-
-
从节点 (Replica):
-
通过
CLUSTER REPLICATE <master-node-id>
命令,将一个新节点设置为某个主节点的从节点。 -
从节点不持有任何槽位,它的核心职责是:
-
复制主节点的数据;
-
在主节点故障时参与故障转移(可能晋升为主节点)。
-
-
✅ 关键点:
节点角色由槽位持有状态和复制关系决定。
执行
CLUSTER NODES
命令可查看所有节点的角色和状态。
二、主从复制过程
Redis Cluster 的复制机制与标准 Redis 主从复制相同(基于异步复制),但由 Cluster 自身管理:
复制流程
-
建立复制关系:
# 在从节点上执行,指向主节点的 ID REPLICAOF <master-ip> <master-port> # 或使用 CLUSTER REPLICATE <master-node-id>
-
全量同步 (Full Sync):
-
从节点首次连接主节点时触发。
-
主节点生成 RDB 快照并发送给从节点。
-
从节点加载 RDB 后,主节点再将期间积压的写命令(通过复制缓冲区)发送给从节点。
-
-
增量同步 (Partial Sync):
-
复制建立后,主节点将收到的所有写命令异步发送给从节点(通过 TCP 长连接)。
-
依赖 Replication ID 和 Offset 标识同步位置:
-
Replication ID
:主节点唯一标识,重启或切换后会更新。 -
Offset
:复制偏移量(类似数据同步的游标)。
-
-
关键机制
-
复制积压缓冲区 (Repl-Backlog):
主节点维护一个环形缓冲区,记录最近发送的命令。若从节点短暂断开后重连,可直接从中获取缺失数据(避免全量同步)。 -
异步复制:
主节点写入后无需等待从节点确认即返回客户端成功,因此存在数据延迟(可能丢失少量数据)。
三、故障自动转移过程
当主节点故障时,Redis Cluster 自动触发故障转移(无需人工干预):
步骤 1:主观下线 (PFAIL)
-
集群中每个节点定期通过 Gossip 协议与其他节点交换心跳。
-
若节点 A 在
cluster-node-timeout
(默认 15 秒)内未收到主节点 B 的响应,则标记 B 为PFAIL
(可能下线)。
步骤 2:客观下线 (FAIL)
-
节点 A 将 B 的
PFAIL
状态传播给其他节点。 -
当某个主节点收到大多数主节点(N/2+1)对 B 的
PFAIL
报告时,它将该节点标记为FAIL
(客观下线) 并向集群广播。
步骤 3:从节点发起选举
-
故障主节点的所有从节点检测到主节点
FAIL
后,进入选举流程:-
等待一段随机延迟(避免多个从节点同时竞争)。
-
向所有主节点发送
FAILOVER_AUTH_REQUEST
投票请求。
-
步骤 4:主节点投票
-
每个主节点收到投票请求后:
-
检查请求的从节点是否属于已
FAIL
的主节点。 -
一个主节点在每一轮选举中只能投一票。
-
优先投票给复制偏移量(
Offset
)最新(数据最完整)的从节点。
-
步骤 5:从节点晋升为主节点
-
获得多数主节点投票(≥ N/2+1)的从节点赢得选举。
-
该从节点执行以下操作:
-
撤销自己的从节点身份。
-
接管原主节点的所有槽位。
-
向集群广播
PONG
消息,通知自身新角色。 -
开始处理客户端请求。
-
步骤 6:集群更新拓扑
-
其他节点更新路由表:
-
原主节点的从节点切换复制到新主节点。
-
客户端收到
MOVED
重定向,指向新主节点。
-
关键设计原理
-
防脑裂 (Split-Brain):
-
故障转移需多数主节点达成共识(投票 + 客观下线判定)。
-
分区中少数节点无法完成故障转移。
-
-
数据一致性优先:
-
投票倾向于选择复制偏移量最大的从节点(数据最新)。
-
-
集群纪元 (Epoch):
-
每次配置变更(如故障转移)会递增一个全局
ConfigEpoch
,用于解决冲突和标识最新状态。
-
故障转移示例时序图
主节点X 宕机 | ↓ 从节点A/B 检测到 X 为 FAIL (客观下线) | \ | 等待随机延迟(避免冲突) ↓ 从节点A 发起投票请求 → 主节点Y/Z | ↑ | 主节点投票(根据Offset优先级) ↓ A 获得多数票 → 晋升为新主节点 | ↓ 广播 PONG 通知集群 | ↓ 从节点B 复制新主节点A
总结
-
主从判定:由槽位持有和复制关系动态决定。
-
数据复制:基于异步复制 + 增量同步(积压缓冲区)。
-
故障转移:
-
主观下线 → 客观下线
-
从节点发起选举
-
主节点投票(优先选数据最新的)
-
从节点晋升并接管槽位
-
-
高可用保障:多数派共识机制 + 数据优先级选举,确保服务快速恢复且数据一致。
🛠 4. 其他增强可用性的措施
-
持久化 (Persistence): 虽然不是直接的“在线可用性”,但 RDB 快照和 AOF 日志保证了在服务器重启后能恢复数据,是数据可靠性的基础。合理的持久化配置可以减少故障转移后的数据丢失量。
-
网络和部署: 将主节点和从节点部署在不同的物理机、机架甚至可用区(AZ)上,避免单点物理故障(如断电、网络中断)同时影响主从节点。
-
配置优化: 合理设置
min-slaves-to-write
和min-slaves-max-lag
选项,确保主节点在足够数量的从节点同步状态良好时才接受写操作,可以防止在主节点故障且未同步足够数据到从节点的情况下进行故障切换导致的数据丢失风险(但会牺牲一些可用性)。 -
客户端处理: 高可用也需要客户端配合。客户端库需要支持 Sentinel 或 Cluster 协议,能够在故障转移后自动重定向请求到新的主节点,并处理重试和连接错误。
-
监控告警: 完善的监控系统(如 Prometheus + Grafana)对节点状态、内存、CPU、网络、复制延迟、Sentinel/Cluster 状态等进行监控,及时发现潜在问题并告警。
-
定期维护: 滚动重启、版本升级、备份验证等。
📌 总结与选择
-
主从复制 (Replication) 是基础,提供数据冗余和读扩展。
-
Redis Sentinel 在主从复制基础上提供自动化故障转移,适合中小规模、非分片的 Redis 高可用部署。
-
Redis Cluster 提供了集数据分片、主从复制、自动化故障转移于一体的高可用和可扩展解决方案,适合大规模、分布式部署,是当前复杂场景下的首选方案。
-
持久化、合理部署、客户端支持、监控告警是支撑任何高可用方案有效运行的必要条件。
选择依据:
-
需要自动故障转移但数据量不大? -> 主从 + Sentinel
-
需要海量数据、高并发、自动故障转移? -> Redis Cluster
-
对数据丢失容忍度极低? -> 优先保证持久化安全配置(AOF + fsync everysec/always)并配合
min-slaves-to-write
,但可能降低写入可用性。 -
预算有限/简单场景? -> 单主多从 + 手动故障转移(不推荐生产环境)。
理解这些机制并根据实际业务需求(数据量、性能要求、容灾要求、运维能力)进行选择和配置,是保障 Redis 服务高可用性的关键。💪🏻