1. Redis Cluster 管理命令概述
Redis Cluster 是 Redis 官方提供的分布式解决方案,它通过数据分片(sharding)的方式实现水平扩展,同时保证了高可用性。作为一名长期使用 Redis 的开发者,我发现 Cluster Management 命令是日常运维中最常用但也最容易忽视的部分。这些命令直接关系到集群的健康状态、节点管理和数据迁移等核心功能。
在 Redis 5.0 版本后,Cluster 命令集已经相当成熟,主要包括节点管理、槽位分配、故障转移和集群配置四大类。与单机版 Redis 不同,集群环境下的命令执行需要考虑节点角色(主/从)和数据分布的特殊性。比如,某些命令只能在主节点执行,而有些命令则对所有节点都适用。
提示:Redis Cluster 默认使用 16384 个哈希槽(slot),这是集群数据分片的基础单元。理解槽位分配原理是掌握集群管理命令的前提。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 节点管理命令详解
2.1 CLUSTER NODES:查看集群拓扑
这是最基础的诊断命令,返回集群中所有节点的详细信息。执行后会看到类似如下的输出:
code复制07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1:30004@31004 slave e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 0 1426238317239 4 connected
e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 127.0.0.1:30002@31002 master - 0 1426238316232 2 connected 5461-10922
每行包含6个关键字段:
- 节点ID:40字符的唯一标识
- 地址端口:IP:端口格式
- 角色:master/slave/myself
- 主节点ID(如果是从节点)
- 最后一次PING发送和接收时间
- 当前纪元(epoch)和连接状态
- 负责的哈希槽范围
在实际运维中,我经常用这个命令快速确认:
- 集群节点数量是否符合预期
- 主从关系是否正确
- 各节点负责的槽位分布
- 节点连接状态是否正常
2.2 CLUSTER MEET:添加新节点
当需要扩展集群时,必须先用此命令让新节点加入集群。基本语法:
code复制CLUSTER MEET <ip> <port> [bus-port]
我曾在生产环境遇到一个典型问题:新节点加入后一直处于handshake状态。排查发现是防火墙阻止了集群总线端口(默认是客户端端口+10000)的通信。这就是为什么建议显式指定bus-port参数:
code复制CLUSTER MEET 10.0.0.5 6379 16379
注意:新节点加入后默认是没有分配槽位的,需要后续手动分配或通过自动平衡工具完成。
2.3 CLUSTER FORGET:移除节点
与MEET相反,这个命令用于从集群中移除某个节点。语法简单:
code复制CLUSTER FORGET <node-id>
但实际使用中有三个关键限制:
- 目标节点必须已经是FAIL状态
- 命令需要在所有存活节点上执行
- 有60秒的窗口期限制
我建议配合以下流程使用:
bash复制# 1. 先标记节点为FAIL
CLUSTER FAILOVER [FORCE|TAKEOVER]
# 2. 在所有其他节点上执行FORGET
redis-cli -c -h <host> -p <port> CLUSTER FORGET <node-id>
# 3. 60秒内完成所有节点的操作
3. 槽位管理命令
3.1 CLUSTER ADDSLOTS:分配槽位
这是初始化集群时最关键的步骤。命令格式:
code复制CLUSTER ADDSLOTS <slot> [slot...]
例如,要给当前节点分配槽位0到500:
bash复制redis-cli CLUSTER ADDSLOTS {0..500}
在早期版本中,我曾遇到槽位分配不连续的报错。后来发现是因为某些槽位已经被其他节点占用。现在我会先用CLUSTER SLOTS检查已有分配情况,再执行ADDSLOTS。
3.2 CLUSTER SETSLOT:修改槽位状态
这个命令有四种子模式,对应不同的操作:
code复制CLUSTER SETSLOT <slot> IMPORTING <source-node-id>
CLUSTER SETSLOT <slot> MIGRATING <destination-node-id>
CLUSTER SETSLOT <slot> NODE <node-id>
CLUSTER SETSLOT <slot> STABLE
最常用的是在线迁移数据时的场景:
bash复制# 在目标节点上准备导入槽位1234
CLUSTER SETSLOT 1234 IMPORTING <source-node-id>
# 在源节点上准备迁移
CLUSTER SETSLOT 1234 MIGRATING <target-node-id>
# 迁移数据
CLUSTER GETKEYSINSLOT 1234 100 | xargs -L 1 redis-cli MIGRATE <target-host> <target-port> "" 0 5000
# 最后在所有节点上更新槽位归属
CLUSTER SETSLOT 1234 NODE <target-node-id>
3.3 CLUSTER DELSLOTS:删除槽位
这个命令主要用于修复异常状态,正常情况下很少使用:
code复制CLUSTER DELSLOTS <slot> [slot...]
我曾在一个故障场景中使用过:某节点异常退出导致部分槽位处于中间状态(neither assigned nor importing),这时需要先DELSLOTS再重新分配。
4. 集群配置与状态命令
4.1 CLUSTER INFO:集群概览
相当于单机版的INFO命令,返回集群级别的统计信息:
code复制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:8
cluster_my_epoch:2
cluster_stats_messages_sent:1483972
cluster_stats_messages_received:1483968
关键指标说明:
- cluster_state:ok表示所有槽位都正常分配
- cluster_slots_assigned:已分配的槽位总数(正常应为16384)
- cluster_size:至少有一个槽位的主节点数量
- current_epoch:集群配置版本号
4.2 CLUSTER SAVECONFIG:保存配置
虽然Redis集群会自动保存节点配置,但在某些维护操作后,我习惯手动执行:
code复制CLUSTER SAVECONFIG
这个命令会将当前集群状态持久化到nodes.conf文件中。在容器化部署时特别有用,可以确保重启后集群拓扑不会丢失。
4.3 CLUSTER RESET:重置节点
危险命令!会清空节点的集群配置,使其退出集群。有两个模式:
code复制CLUSTER RESET [SOFT|HARD]
区别在于:
- SOFT:只重置集群状态,保留数据
- HARD:重置集群状态并清空所有数据
去年我们有个生产事故:运维误在多个节点执行了HARD RESET,导致数据不可恢复。现在我们的操作规范要求:
- 必须先确认节点角色和数据重要性
- 执行前备份nodes.conf和dump.rdb
- 在维护窗口期操作
5. 数据迁移与故障转移命令
5.1 CLUSTER FAILOVER:手动故障转移
在维护场景下,我们可以手动触发主从切换:
code复制CLUSTER FAILOVER [FORCE|TAKEOVER]
三种模式的区别:
- 无参数:标准流程,需要主节点确认
- FORCE:当主节点不可达但可能存活时使用
- TAKEOVER:强制接管,可能造成数据冲突
实际案例:我们曾用TAKEOVER模式处理过网络分区问题。当主节点因网络隔离无法通信时,从节点可以强制升级:
bash复制# 在从节点上执行
CLUSTER FAILOVER TAKEOVER
5.2 CLUSTER REPLICATE:设置主从关系
这个命令让当前节点成为指定主节点的从节点:
code复制CLUSTER REPLICATE <master-node-id>
在调整集群拓扑时特别有用。比如我们需要将一个从节点切换到新的主节点:
bash复制# 1. 先在从节点上执行
CLUSTER REPLICATE <new-master-id>
# 2. 确认复制状态
redis-cli INFO replication
5.3 CLUSTER COUNT-FAILURE-REPORTS:故障检测
这个命令返回某个节点的故障报告数,用于判断节点是否真的不可用:
code复制CLUSTER COUNT-FAILURE-REPORTS <node-id>
集群中的每个节点都会对其他节点进行心跳检测,当超过半数节点认为某节点不可达时,会触发故障转移。我们可以用这个命令监控故障检测进度。
6. 高级运维技巧
6.1 集群批量操作
由于Redis集群的分布式特性,有些操作需要同时在多个节点执行。我常用的两种方式:
- 使用redis-cli的集群模式:
bash复制redis-cli -c -h <host> -p <port> FLUSHALL
- 并行执行工具:
bash复制echo -e 'host1\nhost2' | xargs -I{} -P 8 redis-cli -h {} flushall
6.2 槽位迁移自动化
对于大规模集群,手动迁移槽位效率太低。我通常使用redis-trib.rb(Redis 5前)或redis-cli --cluster reshard(Redis 5+):
bash复制# Redis 5+方式
redis-cli --cluster reshard <host>:<port> \
--cluster-from <source-node-id> \
--cluster-to <target-node-id> \
--cluster-slots <number-of-slots> \
--cluster-yes
6.3 集群备份策略
与单机Redis不同,集群备份需要考虑所有主节点的数据。我的方案是:
- 为每个主节点创建定时备份任务
- 使用SCP将备份文件集中存储
- 记录备份时的集群配置epoch
- 恢复时确保所有节点使用同一时间点的备份
备份脚本示例:
bash复制#!/bin/bash
for port in {7001..7006}; do
redis-cli -h 127.0.0.1 -p $port SAVE
cp /var/lib/redis/$port/dump.rdb /backup/cluster-$(date +%F)/$port.rdb
done
7. 常见问题排查
7.1 集群无法建立连接
典型症状:节点间握手失败,CLUSTER NODES显示handshake状态。
排查步骤:
- 检查防火墙设置,确保集群总线端口开放
- 验证所有节点的bind地址配置
- 检查DNS解析是否一致
- 确认所有节点使用相同的集群密码(如果有)
7.2 槽位未完全分配
错误信息:[ERR] Not all 16384 slots are covered by nodes.
解决方案:
- 使用CLUSTER SLOTS查看当前分配
- 找出未分配的槽位范围
- 使用CLUSTER ADDSLOTS分配给适当节点
- 确认CLUSTER INFO显示所有槽位已分配
7.3 主从切换失败
当FAILOVER命令不生效时,可以检查:
- 从节点与主节点的复制偏移量是否接近
- 集群是否达到故障转移的法定人数
- 节点epoch值是否冲突
- 是否有网络分区阻止了投票通信
我通常会收集以下信息用于分析:
bash复制redis-cli CLUSTER INFO
redis-cli INFO replication
redis-cli CLUSTER NODES | grep myself
8. 性能优化建议
8.1 合理设置集群大小
根据我们的经验值:
- 中小规模集群(<32G):3主3从
- 中等规模(32-128G):6主6从
- 大规模(>128G):按每节点16-32G计算
关键是要确保:
- 每个主节点的数据量不超过32G
- 从节点均匀分布在不同的物理机上
- 控制集群总节点数在合理范围(通常不超过100)
8.2 客户端连接池配置
在集群模式下,客户端需要维护与所有节点的连接。推荐配置:
java复制JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(500); // 总连接数
config.setMaxIdle(100); // 每个节点最大空闲连接
config.setMinIdle(10); // 每个节点最小空闲连接
8.3 监控关键指标
我们团队监控的集群核心指标包括:
- 槽位覆盖率(必须100%)
- 主从复制延迟(<1s)
- 节点内存使用率(<80%)
- 集群消息流量(突增可能预示问题)
- 故障转移次数(异常增加需警惕)
使用Prometheus的示例配置:
yaml复制- job_name: 'redis_cluster'
metrics_path: '/scrape'
static_configs:
- targets: ['redis-exporter:9121']
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: redis-exporter:9121
