Redis Cluster集群架构搭建与数据分片槽位迁移故障转移实战配置

Redis Cluster是Redis官方提供的分布式方案,通过数据分片和自动故障转移实现水平扩展和高可用。在数据库运维中,Redis集群架构的搭建、槽位管理和故障转移是NoSQL选型应用时的核心技能。本文从零开始搭建Redis Cluster,覆盖节点配置、集群初始化、数据迁移、故障模拟和运维监控全流程。

Redis Cluster架构原理与槽位分片机制

Redis Cluster采用虚拟槽分区方式,将整个键空间映射到16384个槽位上。每个节点负责一部分槽位,客户端通过CRC16算法计算key所属的槽位,再定位到目标节点。这种设计相比一致性哈希在数据迁移时更精确,且槽位数量固定避免了rehash开销。

# 槽位计算过程
# slot = CRC16(key) mod 16384

# 例如
# key = "user:1001"
# CRC16("user:1001") = 12345
# slot = 12345 % 16384 = 12345
# 该槽位由哪个节点负责取决于集群分配

# 集群最小建议配置:3主3从(6个节点)
# 主节点负责读写,从节点负责故障转移
# 槽位分配示例(3主节点):
# Node1 (7000): slots 0-5460        (5461个槽)
# Node2 (7001): slots 5461-10922    (5462个槽)
# Node3 (7002): slots 10923-16383   (5461个槽)

每个节点的redis.conf配置:

# redis-7000.conf
port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
appendfsync everysec
bind 0.0.0.0
protected-mode no
# 节点间通信端口(数据端口+10000)
cluster-announce-ip 192.168.1.100
cluster-announce-port 7000
cluster-announce-bus-port 17000

# 内存和淘汰策略
maxmemory 8gb
maxmemory-policy allkeys-lru

# 持久化配置
save 900 1
save 300 10
save 60 10000

集群初始化与节点发现

创建6个节点配置文件并启动服务后,使用redis-cli或redis-trib.rb初始化集群:

# 启动6个Redis实例
for port in 7000 7001 7002 7003 7004 7005; do
    redis-server /opt/redis/redis-${port}.conf
done

# 方式1: redis-cli创建集群(Redis 5.0+)
redis-cli --cluster create     192.168.1.100:7000     192.168.1.100:7001     192.168.1.100:7002     192.168.1.100:7003     192.168.1.100:7004     192.168.1.100:7005     --cluster-replicas 1

# 方式2: 指定主从关系
# 先创建3个主节点
redis-cli --cluster create     192.168.1.100:7000     192.168.1.101:7000     192.168.1.102:7000     --cluster-replicas 0

# 再添加从节点
redis-cli --cluster add-node     192.168.1.100:7001 192.168.1.100:7000     --cluster-slave     --cluster-master-id <node1-id>

# 验证集群状态
redis-cli -p 7000 cluster nodes
redis-cli -p 7000 cluster info

集群初始化后的槽位分配和节点状态验证:

# 查看集群信息
redis-cli -p 7000 cluster info
# cluster_enabled:1
# cluster_slots_assigned:16384
# cluster_slots_ok:16384
# cluster_state:ok
# cluster_known_nodes:6

# 查看节点拓扑
redis-cli -p 7000 cluster nodes
# id  addr         flags   master  ping_sent  pong_recv  epoch  link
# a1.. 192.168.1.100:7000 master -       ...                   connected
# b2.. 192.168.1.101:7000 master -       ...                   connected
# c3.. 192.168.1.102:7000 master -       ...                   connected
# d4.. 192.168.1.100:7001 slave  a1..   ...                   connected
# e5.. 192.168.1.101:7001 slave  b2..   ...                   connected
# f6.. 192.168.1.102:7001 slave  c3..   ...                   connected

# 查看槽位分配
redis-cli -p 7000 cluster slots
# 返回JSON格式,包含每个槽位范围和对应的节点信息

数据分片写入与跨槽操作处理

Redis Cluster要求key必须属于同一个槽位才能执行批量操作。这是数据库迁移实战中常遇到的限制:

# key所属槽位计算
redis-cli -p 7000 cluster keyslot "user:1001"
# (integer) 12345

# 不同槽位的key无法用mget/mset批量操作
redis-cli -p 7000 mset user:1001 "alice" user:2002 "bob"
# (error) CROSSSLOT Keys in request don't hash to the same slot

# 解决方案1: Hash Tags
# 使用{}包裹相同前缀,强制路由到同一槽位
redis-cli -p 7000 mset {user}:1001 "alice" {user}:2002 "bob"
# CRC16计算时只使用{}内的内容
# cluster keyslot "{user}:1001" == cluster keyslot "{user}:2002"

# 解决方案2: Hash Tag设计
# {order}:1001:detail  -> slots[12345]
# {order}:1001:status  -> slots[12345]
# {order}:1001:items   -> slots[12345]
# 同一订单的所有数据在同一槽位,支持批量操作

# 解决方案3: pipeline逐条执行
// Java客户端批量写入
@Test
public void batchWrite() {
    redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
        for (int i = 0; i < 1000; i++) {
            String key = "user:" + i;
            connection.stringCommands().set(
                key.getBytes(),
                ("value" + i).getBytes()
            );
        }
        return null;
    });
}

在线扩容与槽位迁移

当集群存储或吞吐达到瓶颈时,需要添加新节点并执行槽位迁移。这是数据备份恢复和数据库高可用架构中最复杂的操作:

# 1. 添加新主节点
redis-cli --cluster add-node     192.168.1.103:7000     192.168.1.100:7000

# 2. 添加新从节点(指向新主节点)
redis-cli --cluster add-node     192.168.1.103:7001     192.168.1.100:7000     --cluster-slave     --cluster-master-id <new-master-id>

# 3. 重新分片:将槽位从现有节点迁移到新节点
# 交互式分片
redis-cli --cluster reshard 192.168.1.100:7000
# 输入: 需要迁移多少个槽位? 4096
# 输入: 目标节点ID? <new-master-id>
# 输入: 源节点ID? all(从所有节点迁移)或指定节点ID

# 或者通过命令行参数非交互式执行
redis-cli --cluster reshard 192.168.1.100:7000     --cluster-from a1b2c3,d4e5f6     --cluster-to g7h8i9     --cluster-slots 4096     --cluster-yes

# 4. 查看迁移进度
redis-cli -p 7000 cluster nodes

# 5. 验证数据完整性
redis-cli --cluster check 192.168.1.100:7000
# [OK] All nodes agree about slots configuration.
# [OK] All 16384 slots covered.
# [OK] 0 keys found across all nodes (迁移后数据应完整)

槽位迁移的底层过程需要理解MOVED和ASK重定向机制:

# 迁移过程中客户端的行为

# 阶段1:源节点准备迁移slot 8000到目标节点
# 阶段2:客户端访问slot 8000的数据
#   2a. 客户端请求源节点
#   2b. 源节点返回 ASK <target-ip>:<target-port>
#   2c. 客户端向目标节点发送ASKING命令 + 实际请求
#   2d. 目标节点临时处理该请求
# 阶段3:迁移完成,源节点不再持有slot 8000
#   3a. 客户端请求源节点
#   3b. 源节点返回 MOVED 8000 <target-ip>:<target-port>
#   3c. 客户端更新本地槽位映射表
#   3d. 后续请求直接发往目标节点

# ASK是临时的(迁移中),MOVED是永久的(迁移后)
# ASKING命令让目标节点在迁移期间临时接受请求

故障检测与自动故障转移

Redis Cluster通过Gossip协议在节点间传播状态信息,当主节点异常时自动触发故障转移。理解这个过程对于数据库高可用架构的规划至关重要:

# 模拟主节点故障
# 1. 杀掉Node1(7000)的Redis进程
redis-cli -p 7000 debug sleep 60    # 模拟60秒无响应
# 或直接 kill -9 <pid>

# 2. 观察集群状态变化
redis-cli -p 7001 cluster nodes
# Node1标记为 PFAIL (主观下线)
# 30秒后(Node Timeout x 6)标记为 FAIL (客观下线)
# Node1的从节点(Node4)发起选举
# Node4获得多数主节点投票后升级为新主节点
# 槽位0-5460由Node4接管

# 3. 验证故障转移结果
redis-cli -p 7001 cluster nodes
# a1.. 192.168.1.100:7000 fail,failover...  (原主节点标记为fail)
# d4.. 192.168.1.100:7001 master ...        (从节点提升为主节点)

# 4. 数据验证(故障转移期间可能丢失部分未同步数据)
redis-cli -p 7001 get "user:1000"  # 在新主节点上查询

# 5. 恢复原主节点(作为从节点重新加入集群)
redis-server /opt/redis/redis-7000.conf
redis-cli -p 7001 cluster nodes
# a1.. 192.168.1.100:7000 slave d4..        (原主节点变为从节点)

手动故障转移用于计划性维护:

# 在从节点上执行手动故障转移
redis-cli -p 7001 cluster failover

# 可选模式:
# cluster failover takeover  - 强制接管(不等待主节点确认,紧急使用)
# cluster failover force     - 强制故障转移(不检查主节点状态)
# cluster failover           - 正常故障转移(等待主节点同步后切换)

# 主从切换过程:
# 1. 从节点请求主节点停止写入
# 2. 主节点将复制偏移量同步给从节点
# 3. 从节点确认数据已同步
# 4. 从节点发起选举成为新主节点
# 5. 更新集群配置并广播

集群监控与日常运维要点

SQL查询优化和Redis缓存策略的运维有共性之处,都需要建立系统化的监控体系。Redis Cluster的监控关键指标:

# 1. 使用redis-cli --cluster info 查看集群总览
redis-cli --cluster info 192.168.1.100:7000
# 输出示例:
# 192.168.1.100:7000 (a1b2...) -> keys:450000 | slots:5461 | slaves:1
# 192.168.1.101:7000 (c3d4...) -> keys:430000 | slots:5462 | slaves:1
# 192.168.1.102:7000 (e5f6...) -> keys:420000 | slots:5461 | slaves:1
# [OK] 1300000 keys in 3 masters.

# 2. 关键监控指标
# - cluster_state: ok/error
# - cluster_slots_ok: 16384 (应等于总数)
# - cluster_known_nodes: 节点数量
# - 每节点内存使用和key数量
# - 主从复制延迟 (repl_offset差异)
# - 连接数 (connected_clients)
# - key过期和淘汰统计

# 3. 使用Prometheus + redis_exporter监控
# redis_exporter配置
redis_exporter     --redis.addr=192.168.1.100:7000     --redis.password=yourPassword

# PromQL告警规则
# cluster状态异常
# alert: RedisClusterDown
# expr: redis_cluster_state != 1
# for: 1m

# 槽位未全覆盖
# alert: RedisClusterSlotsUnassigned
# expr: redis_cluster_slots_assigned != 16384

# 主从复制延迟过大
# alert: RedisReplicationLag
# expr: redis_replication_offset_diff > 10000

# 4. 慢查询监控
redis-cli -p 7000 config set slowlog-log-slower-than 10000  # 10ms
redis-cli -p 7000 config set slowlog-max-len 128
redis-cli -p 7000 slowlog get 10  # 获取最近10条慢查询

Redis Cluster在数据分表方案中的定位是水平扩展而非高一致性,CAP理论下优先保证AP(可用性和分区容错性)。对于需要强一致性的场景,应考虑使用Redis+Redlock或数据库事务方案替代。分库分表方案选型时需评估集群规模、数据增长速率和一致性要求,制定合理的分片键和Hash Tag策略。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rediscluster-ji-qun-jia-gou-da-jian-yu-shu-ju-fen-pian-cao/

(0)
小编小编
上一篇 2小时前
下一篇 2小时前

相关推荐