第一步:下载 Redis Windows 版
- 下载
Redis-x64-5.0.14.1.zip - 解压到
C:\RedisCluster\redis-base\,确认包含以下文件:redis-server.exe redis-cli.exe redis.windows.conf redis.windows-service.conf
第二步:创建 6 个节点的目录结构
在C:\RedisCluster\下创建:
C:\RedisCluster\ ├── redis-base\ # 解压的原始文件 ├── redis-7000\ │ ├── redis-server.exe # 从 redis-base 复制 │ ├── redis-cli.exe # 从 redis-base 复制 │ └── redis.windows.conf # 从 redis-base 复制后修改 ├── redis-7001\ │ ├── redis-server.exe │ ├── redis-cli.exe │ └── redis.windows.conf ├── redis-7002\ │ ├── redis-server.exe │ ├── redis-cli.exe │ └── redis.windows.conf ├── redis-7003\ │ ├── redis-server.exe │ ├── redis-cli.exe │ └── redis.windows.conf ├── redis-7004\ │ ├── redis-server.exe │ ├── redis-cli.exe │ └── redis.windows.conf └── redis-7005\ ├── redis-server.exe ├── redis-cli.exe └── redis.windows.conf复制命令(PowerShell):
cd C:\RedisCluster # 创建目录并复制文件 1..6 | ForEach-Object { $port = 6999 + $_ $dir = "redis-$port" New-Item -ItemType Directory -Path $dir -Force Copy-Item "redis-base\redis-server.exe" "$dir\" Copy-Item "redis-base\redis-cli.exe" "$dir\" Copy-Item "redis-base\redis.windows.conf" "$dir\" }第三步:修改每个节点的配置文件
用文本编辑器(如 Notepad++、VS Code)打开每个节点的redis.windows.conf,修改以下配置:
redis-7000/redis.windows.conf
# 端口 port 7000 # 集群模式 cluster-enabled yes cluster-config-file nodes-7000.conf cluster-node-timeout 15000 # 持久化 appendonly yes appendfilename "appendonly-7000.aof" # 日志文件 logfile "redis-7000.log" # 允许外部访问 bind 0.0.0.0 protected-mode no # 后台运行(Windows 下建议注释掉,用 start 命令启动) # daemonize yesredis-7001/redis.windows.conf
port 7001 cluster-enabled yes cluster-config-file nodes-7001.conf cluster-node-timeout 15000 appendonly yes appendfilename "appendonly-7001.aof" logfile "redis-7001.log" bind 0.0.0.0 protected-mode noredis-7002/redis.windows.conf
port 7002 cluster-enabled yes cluster-config-file nodes-7002.conf cluster-node-timeout 15000 appendonly yes appendfilename "appendonly-7002.aof" logfile "redis-7002.log" bind 0.0.0.0 protected-mode noredis-7003/redis.windows.conf
port 7003 cluster-enabled yes cluster-config-file nodes-7003.conf cluster-node-timeout 15000 appendonly yes appendfilename "appendonly-7003.aof" logfile "redis-7003.log" bind 0.0.0.0 protected-mode noredis-7004/redis.windows.conf
port 7004 cluster-enabled yes cluster-config-file nodes-7004.conf cluster-node-timeout 15000 appendonly yes appendfilename "appendonly-7004.aof" logfile "redis-7004.log" bind 0.0.0.0 protected-mode noredis-7005/redis.windows.conf
port 7005 cluster-enabled yes cluster-config-file nodes-7005.conf cluster-node-timeout 15000 appendonly yes appendfilename "appendonly-7005.aof" logfile "redis-7005.log" bind 0.0.0.0 protected-mode no关键配置说明:
cluster-enabled yes:开启集群模式cluster-config-file:每个节点必须不同,保存集群拓扑信息cluster-node-timeout:节点超时时间(毫秒)appendonly yes:开启 AOF 持久化
第四步:启动所有 6 个节点
方法一:手动逐个启动
打开 6 个 CMD 窗口,分别执行:
:: 窗口 1 cd C:\RedisCluster\redis-7000 redis-server.exe redis.windows.conf :: 窗口 2 cd C:\RedisCluster\redis-7001 redis-server.exe redis.windows.conf :: 窗口 3 cd C:\RedisCluster\redis-7002 redis-server.exe redis.windows.conf :: 窗口 4 cd C:\RedisCluster\redis-7003 redis-server.exe redis.windows.conf :: 窗口 5 cd C:\RedisCluster\redis-7004 redis-server.exe redis.windows.conf :: 窗口 6 cd C:\RedisCluster\redis-7005 redis-server.exe redis.windows.conf方法二:创建启动脚本
在C:\RedisCluster\下创建start-all.bat:
@echo off echo Starting Redis Cluster Nodes... start "redis-7000" /min cmd /c "cd /d C:\RedisCluster\redis-7000 && redis-server.exe redis.windows.conf" start "redis-7001" /min cmd /c "cd /d C:\RedisCluster\redis-7001 && redis-server.exe redis.windows.conf" start "redis-7002" /min cmd /c "cd /d C:\RedisCluster\redis-7002 && redis-server.exe redis.windows.conf" start "redis-7003" /min cmd /c "cd /d C:\RedisCluster\redis-7003 && redis-server.exe redis.windows.conf" start "redis-7004" /min cmd /c "cd /d C:\RedisCluster\redis-7004 && redis-server.exe redis.windows.conf" start "redis-7005" /min cmd /c "cd /d C:\RedisCluster\redis-7005 && redis-server.exe redis.windows.conf" echo All nodes started! pause双击start-all.bat即可启动全部节点。
第五步:验证节点是否正常启动
:: 检查端口监听 netstat -ano | findstr "7000 7001 7002 7003 7004 7005" :: 测试单个节点 cd C:\RedisCluster\redis-7000 redis-cli.exe -p 7000 ping :: 应返回 PONG第六步:创建集群
在任意节点目录下执行(这里用 redis-7000):
cd C:\RedisCluster\redis-7000 redis-cli.exe --cluster create ^ 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 ^ 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 ^ --cluster-replicas 1注意:Windows CMD 中使用
^换行,PowerShell 中使用`换行。
执行后输出示例:
>>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 127.0.0.1:7004 to 127.0.0.1:7000 Adding replica 127.0.0.1:7005 to 127.0.0.1:7001 Adding replica 127.0.0.1:7003 to 127.0.0.1:7002 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: ... 127.0.0.1:7000 slots:[0-5460] (5461 slots) master M: ... 127.0.0.1:7001 slots:[5461-10922] (5462 slots) master M: ... 127.0.0.1:7002 slots:[10923-16383] (5461 slots) master S: ... 127.0.0.1:7003 replicates ... S: ... 127.0.0.1:7004 replicates ... S: ... 127.0.0.1:7005 replicates ... Can I set the above configuration? (type 'yes' to accept): yes输入yes确认创建。
第七步:验证集群
:: 查看集群状态 redis-cli.exe -p 7000 cluster info :: 查看节点信息 redis-cli.exe -p 7000 cluster nodes :: 测试写入(-c 表示集群模式) redis-cli.exe -c -p 7000 set mykey "Hello Redis Cluster" :: 从其他节点读取 redis-cli.exe -c -p 7002 get mykey预期输出:
cluster_state:ok cluster_slots_assigned:16384 cluster_slots_ok:16384 cluster_slots_pfail:0 cluster_slots_fail:0 cluster_known_nodes:6 cluster_size:3 cluster_current_epoch:6 cluster_my_epoch:1 cluster_stats_messages_ping_sent:... cluster_stats_messages_pong_sent:... cluster_stats_messages_sent:... cluster_stats_messages_ping_received:... cluster_stats_messages_pong_received:... cluster_stats_messages_received:...第八步:关闭集群
创建stop-all.bat:
@echo off echo Stopping Redis Cluster Nodes... redis-cli.exe -p 7000 shutdown redis-cli.exe -p 7001 shutdown redis-cli.exe -p 7002 shutdown redis-cli.exe -p 7003 shutdown redis-cli.exe -p 7004 shutdown redis-cli.exe -p 7005 shutdown echo All nodes stopped! pause常见问题排查
1. 端口被占用
:: 查看占用端口的进程 netstat -ano | findstr "7000" :: 强制结束进程(替换 PID) taskkill /F /PID <进程ID>2. 集群创建失败
:: 删除旧的集群配置 del C:\RedisCluster\redis-7000\nodes-7000.conf del C:\RedisCluster\redis-7001\nodes-7001.conf del C:\RedisCluster\redis-7002\nodes-7002.conf del C:\RedisCluster\redis-7003\nodes-7003.conf del C:\RedisCluster\redis-7004\nodes-7004.conf del C:\RedisCluster\redis-7005\nodes-7005.conf :: 重启所有节点后重新创建集群3. 连接被拒绝
确认 Windows 防火墙已放行端口 7000-7005,或暂时关闭防火墙测试:
:: 管理员权限执行 netsh advfirewall firewall add rule name="Redis Cluster" dir=in action=allow protocol=TCP localport=7000-7005最终目录结构
C:\RedisCluster\ ├── redis-base\ # 原始解压文件(备份) ├── redis-7000\ │ ├── redis-server.exe │ ├── redis-cli.exe │ ├── redis.windows.conf │ ├── nodes-7000.conf # 集群创建后自动生成 │ ├── appendonly-7000.aof # AOF 持久化文件 │ └── redis-7000.log # 日志文件 ├── redis-7001\ │ └── ... ├── redis-7002\ │ └── ... ├── redis-7003\ │ └── ... ├── redis-7004\ │ └── ... ├── redis-7005\ │ └── ... ├── start-all.bat └── stop-all.bat集群创建输出详解
一、创建集群时的输出
1. 哈希槽分配
Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383- Redis 集群共有16384个哈希槽
- 3 个主节点平均分配:
- 主节点 1(7000):槽 0~5460,共 5461 个
- 主节点 2(7001):槽 5461~10922,共 5462 个
- 主节点 3(7002):槽 10923~16383,共 5461 个
2. 副本分配
Adding replica 127.0.0.1:7004 to 127.0.0.1:7000 Adding replica 127.0.0.1:7005 to 127.0.0.1:7001 Adding replica 127.0.0.1:7003 to 127.0.0.1:7002- 初始分配方案:7004 作为 7000 的从节点,以此类推
3. 反亲和性优化
>>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master- Redis 尝试让主从节点分布在不同的物理主机上
- 由于所有节点都在
127.0.0.1(同一台机器),所以发出警告 - 最终优化后的分配:
- 7003 → 复制 7001(而不是 7002)
- 7004 → 复制 7002(而不是 7000)
- 7005 → 复制 7000(而不是 7001)
二、节点信息格式详解
以这行为例:
43c106c042e687c0d3f5d9d43e49ddbe5d3101bd 127.0.0.1:7000@17000 myself,master - 0 1788228508000 1 connected 0-5460| 字段 | 值 | 说明 |
|---|---|---|
| 节点 ID | 43c106c042e687c0d3f5d9d43e49ddbe5d3101bd | 40 位十六进制,集群内唯一标识 |
| 地址 | 127.0.0.1:7000@17000 | 客户端端口 7000,集群总线端口 17000 |
| 标志 | myself,master | myself=当前连接的节点,master=主节点 |
| 主节点 ID | - | 主节点为-,从节点显示其主节点 ID |
| PING 发送时间 | 0 | 最近一次 PING 的时间戳(0=未发送) |
| PONG 接收时间 | 1788228508000 | 最近一次收到 PONG 的时间戳(毫秒) |
| 配置纪元 | 1 | 用于选举和故障转移 |
| 连接状态 | connected | connected=正常,disconnected=断开 |
| 槽位范围 | 0-5460 | 该节点负责的哈希槽范围 |
三、cluster info 输出详解
cluster_state:ok # 集群状态:ok=正常,fail=故障 cluster_slots_assigned:16384 # 已分配的槽数(全部 16384 个已分配) cluster_slots_ok:16384 # 正常工作的槽数 cluster_slots_pfail:0 # 可能故障的槽数(PFAIL) cluster_slots_fail:0 # 确认故障的槽数(FAIL) cluster_known_nodes:6 # 集群已知节点总数 cluster_size:3 # 主节点数量 cluster_current_epoch:6 # 当前集群纪元 cluster_my_epoch:1 # 当前节点的纪元 cluster_stats_messages_ping_sent:53 # 发送的 PING 消息数 cluster_stats_messages_pong_sent:49 # 发送的 PONG 消息数 cluster_stats_messages_sent:102 # 发送的总消息数 cluster_stats_messages_ping_received:44 # 接收的 PING 消息数 cluster_stats_messages_pong_received:53 # 接收的 PONG 消息数 cluster_stats_messages_meet_received:5 # 接收的 MEET 消息数 cluster_stats_messages_received:102 # 接收的总消息数四、cluster nodes 输出详解
ebe956fecf61bd0beb650802c50860f56691eb77 127.0.0.1:7003@17003 slave 3972764149d209482d043c3a456831420e9e458e 0 1788228510737 4 connected| 字段 | 值 | 说明 |
|---|---|---|
| 节点 ID | ebe956... | 7003 节点的唯一标识 |
| 地址 | 127.0.0.1:7003@17003 | 客户端端口 + 集群总线端口 |
| 角色 | slave | 从节点 |
| 主节点 ID | 397276... | 它复制的主节点(7001)的 ID |
| PING 时间 | 0 | |
| PONG 时间 | 1788228510737 | |
| 纪元 | 4 | |
| 状态 | connected | 连接正常 |
| 槽位 | (空) | 从节点不负责槽位 |
五、集群拓扑总结
主节点(Master) 从节点(Slave) 槽位范围 ───────────────────────────────────────────────────────── 7000 (ID: 43c106...) ← 7005 (ID: 53acb7...) 0-5460 7001 (ID: 397276...) ← 7003 (ID: ebe956...) 5461-10922 7002 (ID: 296d75...) ← 7004 (ID: 96ac23...) 10923-16383关键点:
- 每个主节点有一个从节点做备份
- 从节点不分配槽位,只同步主节点数据
- 主节点故障时,从节点会自动提升为主节点
- 集群总线端口 = 客户端端口 + 10000(如 7000 → 17000)
Redis Cluster 模式下主节点宕机后的完整流程
一、故障检测流程
阶段 1:PFAIL(可能故障)
7000 主节点宕机 ↓ 其他节点(7001、7002)通过集群总线定期 PING 7000 ↓ PING 超时(超过 cluster-node-timeout,默认 15 秒) ↓ 7001 将 7000 标记为 PFAIL(可能故障) 7002 将 7000 标记为 PFAIL(可能故障)关键点:
- 每个节点独立判断,不互相通信
- PFAIL 是主观判断,可能是网络抖动导致
- 默认超时时间:
cluster-node-timeout 15000(15 秒)
阶段 2:FAIL(确认故障)
7001 发现 7000 可能故障(PFAIL) ↓ 7001 通过 Gossip 协议向其他节点广播 7000 的 PFAIL 状态 ↓ 其他节点收到广播后,检查自己是否也认为 7000 是 PFAIL ↓ 当超过半数的主节点都认为 7000 是 PFAIL 时 ↓ 7000 被标记为 FAIL(确认故障) ↓ FAIL 状态通过 Gossip 协议广播给所有节点关键点:
- 需要多数主节点确认(3 个主节点中至少 2 个)
- 防止网络分区导致的误判
- FAIL 是客观判断,全集群达成共识
二、故障转移流程
阶段 3:从节点发起选举
7000 被标记为 FAIL ↓ 7000 的从节点 7005 发现主节点故障 ↓ 7005 等待 cluster-node-timeout(15 秒)后开始选举 ↓ 7005 将 currentEpoch(当前纪元)+1 ↓ 7005 向所有主节点发送 FAILOVER_AUTH_REQUEST(投票请求)选举条件:
- 从节点与主节点断开时间不超过
cluster-node-timeout * cluster-slave-validity-factor - 默认:
cluster-slave-validity-factor 10,即 150 秒内
阶段 4:主节点投票
7005 向 7001、7002 请求投票 ↓ 7001 检查: - 是否已经为其他从节点投过票?(每个纪元只能投一票) - 7000 是否确实处于 FAIL 状态? - 7005 的数据是否足够新? ↓ 7001 投票给 7005(返回 FAILOVER_AUTH_ACK) 7002 投票给 7005(返回 FAILOVER_AUTH_ACK) ↓ 7005 获得 2 票(超过主节点数的一半:3/2 = 1.5,向上取整 = 2)投票规则:
- 每个主节点在每个纪元只能投一票
- 从节点需要获得多数主节点的投票(> N/2)
- 3 个主节点,需要至少 2 票
阶段 5:从节点提升为主节点
7005 获得足够票数 ↓ 7005 执行 SLAVEOF NO ONE(取消从节点身份) ↓ 7005 成为新的主节点 ↓ 7005 接管原 7000 的槽位(0-5460) ↓ 7005 向集群广播 PONG 消息,宣布自己成为主节点 ↓ 所有节点更新集群拓扑信息阶段 6:其他从节点重新配置
7005 成为新主节点后 ↓ 原 7000 的其他从节点(如果有)会改为复制 7005 ↓ 在你的集群中,7000 只有一个从节点 7005,所以没有其他从节点需要调整三、完整时间线
T+0 秒 :7000 宕机 T+15 秒 :7001、7002 将 7000 标记为 PFAIL T+15~30 秒 :Gossip 协议传播 PFAIL 状态 T+30 秒 :多数主节点确认,7000 被标记为 FAIL T+30~45 秒 :7005 发起选举 T+45 秒 :7005 获得多数投票 T+45~60 秒 :7005 提升为主节点,接管槽位 T+60 秒 :集群恢复稳定总耗时:约 30-60 秒(取决于 cluster-node-timeout 配置)
四、实际验证步骤
1. 模拟 7000 宕机
:: 方法 1:直接关闭 redis-cli.exe -p 7000 shutdown :: 方法 2:强制结束进程 taskkill /F /PID [7000的进程ID]2. 观察故障转移过程
:: 实时监控集群状态 redis-cli.exe -p 7001 cluster nodes :: 或使用 watch 命令(Linux) watch -n 1 "redis-cli -p 7001 cluster nodes"3. 查看宕机后的状态
:: 查看集群状态 redis-cli.exe -p 7001 cluster info :: 预期输出 cluster_state:ok # 集群仍然正常 cluster_slots_ok:16384 # 所有槽位都正常 cluster_known_nodes:5 # 节点数从 6 变为 5 cluster_size:3 # 主节点数仍然是 34. 查看新的主从关系
redis-cli.exe -p 7001 cluster nodes预期输出:
# 7005 已经成为新的主节点 53acb78cd81948ab40eb596b3c68b9c2244fefaf 127.0.0.1:7005@17005 master - 0 ... 7 connected 0-5460 # 7000 显示为 fail 43c106c042e687c0d3f5d9d43e49ddbe5d3101bd 127.0.0.1:7000@17000 master,fail - 0 ... 1 disconnected五、恢复 7000 节点
7000 恢复后的角色
:: 重启 7000 cd E:\Redis\redis-cluster\7000 redis-server.exe redis.conf :: 查看 7000 的状态 redis-cli.exe -p 7000 cluster nodes7000 恢复后的角色:
7000 重新加入集群 ↓ 发现自己原来的槽位已经被 7005 接管 ↓ 7000 自动成为 7005 的从节点 ↓ 新的主从关系:7005(主)← 7000(从)六、关键配置参数
# redis.conf 中的集群配置 # 节点超时时间(毫秒) cluster-node-timeout 15000 # 从节点有效性因子 cluster-slave-validity-factor 10 # 从节点迁移 cluster-migration-barrier 1 # 集群是否需要完整覆盖所有槽位才对外服务 cluster-require-full-coverage yes七、故障转移流程图
┌─────────────┐ │ 7000 宕机 │ └──────┬──────┘ ↓ ┌─────────────────────┐ │ 其他节点 PING 超时 │ (15秒) │ 标记为 PFAIL │ └──────┬──────────────┘ ↓ ┌─────────────────────┐ │ Gossip 协议传播 │ │ 多数主节点确认 │ │ 标记为 FAIL │ └──────┬──────────────┘ ↓ ┌─────────────────────┐ │ 7005 发起选举 │ │ currentEpoch + 1 │ │ 请求投票 │ └──────┬──────────────┘ ↓ ┌─────────────────────┐ │ 主节点投票 │ │ 7001、7002 投票 │ │ 7005 获得 2 票 │ └──────┬──────────────┘ ↓ ┌─────────────────────┐ │ 7005 提升为主节点 │ │ SLAVEOF NO ONE │ │ 接管槽位 0-5460 │ └──────┬──────────────┘ ↓ ┌─────────────────────┐ │ 集群恢复稳定 │ │ 7005 成为新主节点 │ └─────────────────────┘八、注意事项
- 数据一致性:故障转移期间,写入操作可能失败
- 客户端重定向:客户端需要处理 MOVED 和 ASK 重定向
- 网络分区:如果网络分区导致主节点之间无法通信,可能出现脑裂
- 从节点数据滞后:如果从节点数据落后太多,可能无法成为主节点
- 监控告警:生产环境应配置监控,及时发现节点故障
总结
7000 宕机后的完整流程:
- 检测:其他节点 PING 超时,标记 PFAIL(15 秒)
- 确认:多数主节点确认,标记 FAIL(15-30 秒)
- 选举:7005 发起选举,获得多数投票(30-45 秒)
- 接管:7005 提升为主节点,接管槽位(45-60 秒)
- 恢复:7000 重启后自动成为 7005 的从节点
整个过程自动完成,无需人工干预,集群在故障转移期间保持可用。