Redis高可用方案:Redis Cluster集群模式

目录

1、概念

2、集群架构与角色

3、核心工作机制

3.1 请求路由 (Request Routing)

3.2 节点间通信 (Gossip Protocol)

3.3 故障检测 (Failure Detection)

3.4 故障转移 (Failover)

3.5 槽位迁移 (Slot Migration) - 集群扩容/缩容/再平衡

4、关键特性与限制

5、部署方案

5.1 集群架构规划

5.2 节点配置(所有节点)

5.3 集群部署流程

5.4 主从节点配置详解

5.5 槽管理操作

5.6 监控

6、高可用性与数据安全分析

7、适用场景与选择


1、概念

原理: Redis 官方的分布式解决方案。将数据自动分片到多个节点(每个节点是主从结构)。数据按  划分(共 16384 个槽),每个节点负责一部分槽。主要解决单机 Redis 在内存容量、吞吐量和高可用性方面的瓶颈。

核心目标与解决的问题:

  • 海量数据存储: 突破单机内存限制,将数据分片(Shard) 存储在多个节点上,总容量是集群中所有节点内存之和。

  • 高吞吐量: 通过分片,将读写请求分散到多个节点并行处理,显著提升整体吞吐量。

  • 高可用性 (HA): 每个数据分片都是一个主从复制组(Master-Replica Group)。当主节点故障时,集群能自动进行故障转移,提升从节点为主节点,保证服务可用性。

  • 去中心化与自治: 集群节点间通过 Gossip 协议交换信息,管理配置和故障检测。不需要像 Sentinel 那样的独立协调组件(虽然内部机制类似)。

  • 水平扩展: 可以方便地通过增加节点来扩展集群的容量和吞吐量。

核心概念:数据分片 (Sharding) 与 Hash Slot (哈希槽):

  • Redis Cluster 将整个数据空间划分为 16384 个固定数量的槽 (Slot) (0-16383)。

  • 每个键 (Key) 通过 CRC16 算法计算出一个 16 位的哈希值,然后对这个值取模 16384 (CRC16(key) % 16384),确定其属于哪个 Slot。

  • 每个主节点 (Master) 负责处理一组 Slot 的子集。 集群启动或配置变更时,会明确分配哪些 Slot 由哪个主节点负责。

  • 优点:

    • 解耦数据与节点: 数据分布由 Slot 决定,节点变化时只需移动 Slot 映射关系,不需要重新计算所有 Key 的哈希。

    • 可管理性: 固定数量的 Slot 便于管理、迁移和再平衡。

    • 高效路由: 客户端或代理可以快速计算出 Key 对应的 Slot,进而找到负责节点。

优点: 真正的分布式,支持水平扩展(存储容量和吞吐量)、高可用。

缺点: 架构更复杂;不支持跨槽的事务(Multi-Key 操作限制);客户端需要支持 Cluster 协议;某些管理操作(如迁移大 key)可能影响性能。

2、集群架构与角色

节点角色 (Node Roles):

  • 主节点 (Master):

    • 负责处理其分配的 Slot 的所有读写请求。

    • 存储数据。

    • 参与故障检测与投票。

  • 从节点 (Replica):

    • 复制其关联的主节点数据(异步复制)。

    • 处理读请求(可配置 replica-read-only)。

    • 在主节点故障时,参与故障转移竞选,有可能被提升为新的主节点。

  • 一个集群至少需要 3 个主节点才能正常工作(满足故障转移投票要求)。 通常建议为每个主节点配置至少 1 个从节点以实现高可用。

集群拓扑:

  • 一个 Redis Cluster 由多个节点(通常是 6 个或更多:3 主 + 3 从)组成。

  • 每个节点都知道集群中其他所有节点的状态信息(通过 Gossip 协议)。

  • 数据分布在所有主节点上(通过 Slot)。

  • 从节点提供数据冗余和故障转移能力。

示例 (3 主 3 从):每个主节点负责约 1/3 的 Slot,其从节点复制其数据。

Master1 (Slots 0-5460)  ---- Replica1 (of Master1)
Master2 (Slots 5461-10922) ---- Replica2 (of Master2)
Master3 (Slots 10923-16383) ---- Replica3 (of Master3)

3、核心工作机制

3.1 请求路由 (Request Routing)

客户端如何知道一个 Key 请求应该发给哪个节点?

1> 客户端重定向 (MOVED/ASK): 最常用且推荐的方式。 客户端库需要支持 Cluster 协议。

  • 首次请求: 客户端随机连接集群中任一节点发送命令。

  • 命中 Slot: 如果该 Slot 由当前节点负责,直接执行命令并返回结果。

  • 未命中 Slot (MOVED 错误): 如果该 Slot 不属于当前节点负责,节点返回 MOVED <slot> <target-ip>:<target-port> 错误。

    • 客户端收到 MOVED 错误后,更新本地 Slot 映射缓存,然后重新连接到正确的 <target-node> 发送请求。

  • ASK 重定向 (迁移中): 当 Slot 正在从一个节点 (source) 迁移到另一个节点 (target) 时:

    • 如果 Key 还在 source 节点,source 节点正常处理。

    • 如果 Key 已迁移到 target 节点,source 节点返回 ASK <slot> <target-ip>:<target-port> 错误。

    • 客户端收到 ASK 后,不更新本地缓存,而是临时连接到 target 节点,并在发送命令前先发送 ASKING 命令,然后发送原命令。target 节点在迁移期间会接受标记了 ASKING 的请求。

  • 智能客户端 (Smart Client): 成熟的 Redis 客户端库 (Lettuce, Jedis, Redisson, ioredis) 都实现了 Cluster 支持。它们在内部维护一个 Slot 到节点地址的映射缓存。通过 CLUSTER SLOTS 命令或处理 MOVED/ASK 响应来更新缓存,尽量将请求直接发送到正确的节点,减少重定向次数。

2> 代理模式 (Proxy): 使用独立的代理服务器 (如 Twemproxy, Codis, Redis Cluster Proxy)。客户端连接代理,代理负责计算 Slot 并转发请求到正确的后端节点。对客户端透明,但增加了额外跳转和潜在瓶颈。

3.2 节点间通信 (Gossip Protocol)

集群节点如何感知彼此的状态(在线、下线、角色、Slot 分配)?

  • PING/PONG 消息: 每个节点默认每秒会随机选择几个其他节点发送 PING 消息。接收节点回复 PONG 消息。

  • 消息内容: PING/PONG 消息携带发送节点自身的信息以及它所知道的部分其他节点的信息(不是全部,Gossip 的特点)。

  • 传播: 节点通过持续交换 PING/PONG 消息,以指数级速度将集群状态信息传播到所有节点。最终所有节点会达到对集群状态的一致视图(最终一致性)。

  • 信息类型:

    • 节点 ID、IP、端口、角色 (主/从)、状态。

    • 节点负责的 Slot 信息。

    • 主节点的从节点信息。

    • 节点下线/故障信息。

  • 优点: 去中心化、容错性好(部分节点失效不影响整体)、带宽消耗相对可控(每次只发部分信息)。

  • 缺点: 状态传播有延迟(最终一致性),不适用于要求强一致性的场景。

3.3 故障检测 (Failure Detection)

如何判断一个节点是否故障?

  • 主观下线 (PFAIL - Possible Fail):

    • 节点 A 在 cluster-node-timeout (默认 15 秒) 内一直未能与节点 B 成功通信(未收到有效 PONG 回复)。

    • 节点 A 会在其本地将节点 B 标记为 PFAIL

    • PFAIL 是主观的,只代表节点 A 认为 B 可能下线。

  • 客观下线 (FAIL):

    • 当节点 A 将节点 B 标记为 PFAIL 后,它会通过 PING/PONG 消息询问集群中其他节点对节点 B 的判断。

    • 如果集群中大多数主节点> N/2,N 是主节点总数)在一定时间窗口内都报告节点 B 为 PFAIL 状态。

    • 节点 A 就会将节点 B 标记为 FAIL,并将这个 FAIL 状态通过 Gossip 广播给整个集群。

    • 一旦节点 B 被标记为 FAIL,集群将触发对该节点负责的 Slot 的故障转移(如果它是主节点)。

3.4 故障转移 (Failover)

当负责某些 Slot 的主节点被标记为 FAIL 时,如何恢复服务?

1> 从节点资格检查: 故障主节点的所有从节点会检查自己是否有资格参与选举:

  • 与主节点断开连接的时间不能超过 (cluster-node-timeout * cluster-replica-validity-factor) + 1000 毫秒(默认 15s * 10 + 1000ms = 160s)。如果断开太久,数据可能太旧,失去资格。

2> 从节点延迟检查: 有资格的从节点会等待一段延迟时间 (replica 排名 * 1000 + random),排名由复制偏移量 (repl_offset) 决定,偏移量最大的(数据最新的)从节点排名为 0。数据最新的从节点等待时间最短。

3> 发起选举: 等待时间结束后,从节点向集群中所有主节点发送 FAILOVER_AUTH_REQUEST 消息,请求投票。

4> 主节点投票:

  • 每个主节点在一个配置纪元 (epoch) 内对每个主节点故障事件只能投一次票

  • 主节点收到请求后,如果满足以下条件则投票 (FAILOVER_AUTH_ACK):

    • 请求的从节点所属的主节点确实被标记为 FAIL。

    • 该主节点在当前纪元尚未投票。

    • 请求的从节点是有资格的(断开时间未超限)。

5> 赢得选举: 从节点如果在 2 * cluster-node-timeout 时间内收到大多数主节点 (> N/2) 的投票,则赢得选举。

6> 提升为主节点: 赢得选举的从节点:

  • 更新自身状态为主节点 (MASTER)。

  • 接管原主节点负责的所有 Slot。

  • 通过 PONG 消息向集群广播自己成为新主节点的信息。

7> 其他从节点切换: 原主节点下的其他从节点会检测到新主节点上线(通过 Gossip),并开始向新主节点发起复制 (REPLICAOF)。

8> 旧主节点恢复: 如果旧主节点重新上线,它会发现自己负责的 Slot 已被新主节点接管,并自动成为新主节点的从节点。

3.5 槽位迁移 (Slot Migration) - 集群扩容/缩容/再平衡

如何将 Slot 从一个节点移动到另一个节点?

1> 发起迁移命令: 使用 CLUSTER SETSLOT <slot> IMPORTING <source-node-id> 在目标节点上设置 Slot 为 IMPORTING 状态。使用 CLUSTER SETSLOT <slot> MIGRATING <target-node-id> 在源节点上设置 Slot 为 MIGRATING 状态。

2> 迁移键值对:

  • 使用 CLUSTER GETKEYSINSLOT <slot> <count> 在源节点获取属于该 Slot 的 Key 列表。

  • 对每个 Key,使用 MIGRATE <target-host> <target-port> "" 0 <timeout> KEYS <key1> [<key2> ...] 命令将 Key 的数据原子性地迁移到目标节点。迁移过程中,源节点会阻塞对该 Key 的操作直到迁移完成。

3> 更新 Slot 分配: 当 Slot 中的所有 Key 都迁移完毕后,使用 CLUSTER SETSLOT <slot> NODE <target-node-id> 命令在所有主节点上执行,将该 Slot 的负责权正式分配给目标节点。这个命令会通过 Gossip 传播到整个集群。

4> 客户端处理 (ASK 重定向): 在迁移过程中,客户端请求:

  • 如果 Key 仍在源节点,源节点正常处理。

  • 如果 Key 已迁移到目标节点,源节点返回 ASK 重定向,引导客户端临时访问目标节点。

  • 迁移完成后,客户端会收到 MOVED 重定向,更新本地缓存指向目标节点。

5> 自动化工具: 实际操作中,强烈建议使用 redis-cli --cluster reshard <host>:<port> 或 redis-cli --cluster rebalance <host>:<port> 等工具来自动化完成 Slot 迁移和集群再平衡,它们内部封装了上述步骤并处理了复杂性。

4、关键特性与限制

1> 最小主节点数: 3 个(满足投票大多数 > N/2 的要求,3/2=1.5,取整为2,所以需要至少2票)。

2> 键操作限制:

  • 多键操作限制: 涉及多个 Key 的命令(如 MGETMSETDEL key1 key2SINTER/SUNION, Lua 脚本中的多键操作)要求所有 Key 必须位于同一个 Slot。否则会返回 CROSSSLOT 错误。解决方法:

    • 使用 Hash Tags:在 Key 中使用 {} 包裹一个部分(如 user:{123}:profileuser:{123}:orders),集群只根据 {} 内的字符串计算 Slot,确保相关 Key 落在同一 Slot。

    • 客户端拆分命令,分别发送到不同节点,再合并结果。

  • 事务限制: 事务 (MULTI/EXEC) 中的所有命令同样要求 Key 在同一个 Slot(因为事务在单个节点执行)。同样依赖 Hash Tags

  • Lua 脚本限制: 脚本中的所有 Key 必须由执行脚本的节点负责(即在同一节点),同样要求使用 Hash Tags 或确保脚本只操作单个 Key。Redis 7.0 引入了 functions,对 Cluster 更友好。

3> 从节点读: 支持,通过 READONLY 命令或配置 replica-read-only yes。客户端需显式连接到从节点。存在读取到旧数据(复制延迟) 的风险。

4> Pub/Sub: 默认情况下,发布和订阅操作会广播到所有节点。这意味着 PUBLISH 命令会在发布者连接的节点执行,然后广播到集群所有节点,再由这些节点发送给本地连接的订阅者。也可以使用 SSUBSCRIBE 只订阅特定分片 (shardchannel)。

5> 不支持多数据库: 集群模式下只支持 DB 0SELECT 命令被禁用。

6> 批量操作效率: 涉及多个 Slot 的批量操作效率低于单机 Redis,因为需要与多个节点通信。

7> 配置管理: 集群配置信息自动在节点间同步(通过 Gossip 和 CLUSTER 命令)。节点列表和 Slot 分配信息存储在 nodes.conf 文件中。

5、部署方案

5.1 集群架构规划

最小生产环境要求:

  • 6个节点:3个主节点(Master)+ 3个从节点(Replica)

  • 16384个哈希槽:平均分配到主节点

  • 节点分布:建议跨物理机/可用区部署

示例拓扑(3主3从):

节点1: 192.168.1.101:6379 (主) - 槽范围 0-5460
节点2: 192.168.1.102:6379 (主) - 槽范围 5461-10922
节点3: 192.168.1.103:6379 (主) - 槽范围 10923-16383
节点4: 192.168.1.104:6379 (从) -> 复制节点1
节点5: 192.168.1.105:6379 (从) -> 复制节点2
节点6: 192.168.1.106:6379 (从) -> 复制节点3

5.2 节点配置(所有节点)

通用配置项 (redis.conf):

# 基础配置
port 6379
daemonize yes
pidfile /var/run/redis_6379.pid
logfile "/var/log/redis/redis_6379.log"
dir /data/redis

# 集群配置
cluster-enabled yes               # 启用集群模式
cluster-config-file nodes-6379.conf # 集群状态文件
cluster-node-timeout 15000        # 节点超时时间(毫秒)
cluster-replica-validity-factor 10 # 副本有效性因子
cluster-migration-barrier 1       # 主节点最少副本数

# 安全配置(推荐)
requirepass "ClusterPwd123"       # 节点访问密码
masterauth "ClusterPwd123"        # 主从认证密码

# 性能优化
maxmemory 8gb                     # 根据内存调整
maxmemory-policy volatile-lru     # 内存淘汰策略
appendonly yes                    # 开启AOF
appendfsync everysec              # AOF刷盘策略

关键参数说明:

  • cluster-node-timeout:节点通信超时时间,影响故障检测速度

  • cluster-replica-validity-factor:控制副本是否参与故障转移(0=始终参与)

  • requirepass 和 masterauth:必须相同,用于节点间通信认证

5.3 集群部署流程

1> 准备节点

# 在所有节点创建数据目录
sudo mkdir -p /data/redis
sudo chown redis:redis /data/redis

# 复制配置文件
sudo cp redis.conf /etc/redis/redis_6379.conf

# 启动所有节点
redis-server /etc/redis/redis_6379.conf

2> 创建集群

# 使用redis-cli创建集群
redis-cli --cluster create \
  192.168.1.101:6379 \
  192.168.1.102:6379 \
  192.168.1.103:6379 \
  192.168.1.104:6379 \
  192.168.1.105:6379 \
  192.168.1.106:6379 \
  --cluster-replicas 1 \
  -a ClusterPwd123

命令参数说明:

  • --cluster-replicas 1:每个主节点分配1个副本

  • -a:集群密码认证

3> 验证集群状态

# 连接任意节点
redis-cli -c -h 192.168.1.101 -p 6379 -a ClusterPwd123

# 检查集群状态
> CLUSTER INFO
cluster_state:ok          # 集群状态正常
cluster_slots_assigned:16384  # 所有槽已分配
cluster_slots_ok:16384
cluster_known_nodes:6     # 节点数量正确

# 查看节点拓扑
> CLUSTER NODES

5.4 主从节点配置详解

主节点配置要点

  • 无需特殊配置:主节点自动处理分片数据

  • 槽分配:创建集群时自动分配,也可手动调整

  • 写操作:只处理属于自己槽的写请求

从节点配置要点

  • 自动复制:创建集群时通过--cluster-replicas参数指定

  • 故障转移:主节点故障时,副本自动晋升为主节点

  • 只读模式:默认只处理读请求

手动添加副本节点:

# 语法:redis-cli --cluster add-node <新节点> <目标主节点> --cluster-slave
redis-cli --cluster add-node 192.168.1.107:6379 192.168.1.101:6379 \
  --cluster-slave \
  -a ClusterPwd123

5.5 槽管理操作

1> 查看槽分配

redis-cli --cluster check 192.168.1.101:6379 -a ClusterPwd123

2> 重新分片

redis-cli --cluster reshard 192.168.1.101:6379 -a ClusterPwd123

交互过程:

  1. 输入要迁移的槽数量(如1000)

  2. 输入目标节点ID

  3. 输入源节点ID(或输入"all"从所有节点迁移)

  4. 输入"yes"开始迁移

3> 手动迁移单个槽

# 1. 设置槽状态
redis-cli -h 192.168.1.101 -a ClusterPwd123 CLUSTER SETSLOT 1213 MIGRATING <目标节点ID>

# 2. 迁移键值
redis-cli -h 192.168.1.101 -a ClusterPwd123 CLUSTER GETKEYSINSLOT 1213 100 | \
  xargs -L 1 redis-cli -h 192.168.1.101 -a ClusterPwd123 MIGRATE 192.168.1.102 6379 "" 0 5000 KEYS

# 3. 完成迁移
redis-cli -h 192.168.1.102 -a ClusterPwd123 CLUSTER SETSLOT 1213 IMPORTING <源节点ID>
redis-cli -h 192.168.1.101 -a ClusterPwd123 CLUSTER SETSLOT 1213 NODE <目标节点ID>
redis-cli -h 192.168.1.102 -a ClusterPwd123 CLUSTER SETSLOT 1213 NODE <目标节点ID>

5.6 监控

# 检查集群健康状态、Slot 覆盖、主从配置
redis-cli --cluster check <host>:<port> -a <password>

# 查看槽分布
redis-cli --cluster info <host>:<port> -a <password>

# 内存分析
redis-cli -c --bigkeys -a <password>

# 查看集群整体状态(状态、Slot 分配、节点数等)
redis-cli -c -p <port> CLUSTER INFO

# 查看集群所有节点信息(ID、角色、状态、负责 Slot、主从关系等)最详细!
redis-cli -c -p <port> CLUSTER NODES

6、高可用性与数据安全分析

  • 主节点故障: 通过主从复制 + 自动故障转移保障可用性(如前所述)。

  • 从节点故障: 仅影响该副本的冗余。主节点继续服务。从节点恢复后重新同步。

  • 多节点故障:

    • 如果故障的主节点数超过集群剩余主节点数的一半 (> N/2),集群将无法达成共识进行故障转移,进入 FAIL 状态,停止服务(如果 cluster-require-full-coverage=yes)。

    • 如果故障的是从节点,只要其主节点还在,不影响服务。

  • 网络分区 (脑裂):

    • 可能发生。Redis Cluster 使用 "大多数原则" 来防御脑裂:

      • 只有拥有大多数主节点的分区才能进行故障转移和写入操作。

      • 少数分区中的主节点会被标记为 FAIL,无法接受写入(即使它们在线)。

    • 这可能导致少数分区中的数据丢失(如果客户端在少数分区中向旧主节点写入)。配置 min-replicas-to-write (虽然原生 Cluster 没有直接等同,但类似思想) 可以在一定程度上缓解,但 Redis Cluster 本身对此无完美解决方案。这是 CAP 中 AP 的选择。

7、适用场景与选择

  • 选择 Redis Cluster 当:

    • 数据量超过单机内存。

    • 读写吞吐量超过单机 Redis 能力。

    • 需要高可用性,且能容忍故障转移期间短暂不可用和极小概率的异步复制丢失。

    • 应用程序能处理 MOVED/ASK 重定向或使用支持 Cluster 的客户端/代理。

  • 考虑其他方案当:

    • 数据量小,单机 + 主从 + Sentinel 足够。

    • 需要强一致性保证。

    • 重度依赖多 Key 操作、事务、Lua 脚本且无法使用 Hash Tags

    • 需要跨地域部署(Redis Cluster 对网络延迟敏感,跨地域部署复杂,通常用主动复制如 CRDTs 或代理层处理)。

    • 运维复杂度要求低(Cluster 比 Sentinel/单机复杂)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熙客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值