Redis集群实战:从主从复制、哨兵到分片扩容的架构演进
搭建过 Redis 主从复制面试也背过主从复制和哨兵的原理但真正到了生产环境总会遇到一个绕不开的追问已经有了主从复制为什么还要费劲引入 Redis 集群这个问题不是简单的“数据量大了切片扩容”一句话就能说清的。主从复制解决的是读压力和高可用而 Redis 集群解决的是数据容量、写入吞吐、节点自治和故障转移的一体化问题。两者职责不同不能互相替代。本文直接对比主从复制、哨兵模式和 Redis 集群的定位然后给出部署、验证、扩缩容和排查的完整思路。不看空泛概念重点看它们在真实业务里分别解决什么问题、什么时候必须升级到集群。1. 核心能力速览能力项说明数据冗余主从复制依赖从节点副本集群模式下每个分片含主节点和从节点数据按 Slot 分布高可用主从复制本身不具备自动故障转移哨兵模式基于 Sentinel 实现集群模式通过 Gossip 和投票实现自动故障转移水平扩展集群支持在线增加分片迁移 Slot 完成扩缩容主从复制只能纵向扩展从节点数量写入能力主从复制只有主节点提供写入集群通过多主分片分摊写入请求数据分布集群按 16384 个 Slot 划分数据客户端通过 CRC16 计算定位节点启动方式命令行启动多个 redis-server 实例或使用 redis-cli --cluster 命令完成集群创建当前定位满足单机容量不足、高写入并发、自动故障转移、多节点运维一体化场景需要先说清楚一个常见误区Redis 集群并非完全替代主从复制。集群的分片数据同样依赖节点间的主从复制机制它是“分片 复制 高可用”的组合方案。2. 主从复制解决了什么问题主从复制的核心价值是让数据在多个 Redis 实例上保留副本。一个主节点负责写和读一个或多个从节点同步主节点的数据并可以分担读请求。这套架构解决了两类问题第一单点故障时数据不直接丢失从节点还在主节点挂了可以人工切到从节点第二读多写少的业务可以把读流量分散到多个从节点降低主节点的压力。但主从复制有几个关键缺陷容易被忽略。首先主节点仍然是唯一写入入口单节点的内存容量上限就是整个系统的容量上限。比如一台 32G 内存的服务器Redis 存到了 20G 以上无论加多少个从节点容量问题都没有解决。其次从节点是异步复制主节点发生故障时尚未同步到从节点的写命令会丢失。最后主节点宕机后需要人工干预或者依赖额外组件完成切换主从复制本身没有自动化能力。所以在生产环境主从复制通常不是终点而是更复杂架构的第一步。3. 哨兵模式是被逼出来的高可用方案主从模式下主节点宕机系统怎么办如果靠运维手动执行 SLAVEOF、选新主、改客户端指向故障恢复时间以分钟甚至小时计业务早就中断了。于是哨兵模式被引入。Sentinel 是 Redis 官方提供的高可用方案。它独立于主从节点运行通过监控、通知、自动故障转移三个动作实现高可用。当主节点被判定为主观下线再经过多个 Sentinel 节点确认后进入客观下线Sentinel 会选举新的主节点并把其他从节点重新指向新主节点。哨兵模式解决了故障转移的自动化问题但仍然没有解决容量和写入吞吐问题。即便部署了三主三从的哨兵架构写入还是落在单一主节点数据容量还是受制于单节点内存。这个时候业务量继续上涨Redis 集群就该出场了。4. Redis 集群的真正价值容量、分片、自治Redis 集群采用无中心化架构节点之间通过 Gossip 协议交换状态。数据按 key 通过 CRC16 算法计算对 16384 个槽位取模落在具体的哈希槽上每个节点负责一部分槽位。集群解决了主从复制和哨兵模式解决不了的三件事第一容量上限变成了整个集群的内存总和。原来单节点最多 32G现在用 6 台机器组集群理论容量就能接近 192G。实际还要考虑数据倾斜和节点故障预留但横向扩展的方向已经被打开了。第二写入吞吐不再受单节点限制。多主分片可以同时处理写请求客户端根据 key 的哈希结果路由到不同节点。当一个分片成为瓶颈时可以继续增加分片并迁移槽位整个集群的写能力能持续扩张。第三故障转移和节点自治内置在集群协议里。集群中每个分片可以配置从节点当主节点发生故障时从节点通过集群内部投票机制提升为新主节点整个切换由集群自身完成不需要额外部署 Sentinel。5. Redis 集群部署环境准备5.1 节点规划Redis 集群至少要 3 个主节点才能组成完整集群每个主节点建议至少配 1 个从节点这样任意一个主节点故障集群仍然可用。所以生产环境最基础是 6 个节点3 主 3 从。本地学习场景可以用一台机器启动 6 个 redis-server 进程端口分别设置为 7001 到 7006。这种方式适合验证流程不适合压测和生产。如果有多台服务器规划时要注意网络连通性、端口开放、内存和磁盘预留。每个节点的内存建议预留集群状态、AOF 缓冲、后台 RDB 持久化所需的空间不要直接把物理内存打满。5.2 配置文件准备每个 Redis 实例需要独立配置文件。以下是 7001 端口实例的配置模板其他端口只需替换对应项port 7001 cluster-enabled yes cluster-config-file nodes-7001.conf cluster-node-timeout 15000 appendonly yes daemonize yes protected-mode no bind 0.0.0.0 dir /data/redis-cluster/7001关键配置说明cluster-enabled yes开启集群模式。cluster-config-file指定节点状态文件这个文件由集群自动维护不能手动改名或删除。cluster-node-timeout设置节点超时时间超过该时间未收到 Ping 回复节点会被判定为疑似故障。bind 0.0.0.0表示监听所有网卡生产环境应改为内网 IP避免直接暴露到公网。dir设置为独立目录每个节点使用独立的持久化目录避免多个实例共用数据目录导致文件冲突。5.3 启动实例redis-server /data/redis-cluster/7001/redis.conf redis-server /data/redis-cluster/7002/redis.conf redis-server /data/redis-cluster/7003/redis.conf redis-server /data/redis-cluster/7004/redis.conf redis-server /data/redis-cluster/7005/redis.conf redis-server /data/redis-cluster/7006/redis.conf启动后用ps -ef | grep redis确认 6 个进程都处于运行状态。也可以直接redis-cli -p 7001 ping返回 PONG 表示实例启动成功。这时实例之间还没有建立集群关系需要执行创建集群命令。6. 创建 Redis 集群与验证方法6.1 创建集群早期版本依赖 redis-trib.rb 脚本现在 Redis 5.0 之后推荐直接使用 redis-cli 内置的 cluster 子命令redis-cli --cluster create \ 192.168.1.101:7001 192.168.1.102:7002 192.168.1.103:7003 \ 192.168.1.104:7004 192.168.1.105:7005 192.168.1.106:7006 \ --cluster-replicas 1--cluster-replicas 1表示每个主节点分配 1 个从节点命令执行后 Redis 会打印节点分配方案确认后输入 yes 完成创建。集群创建完成后可以通过redis-cli -p 7001 cluster info查看集群状态重点关注cluster_state:ok和cluster_known_nodes数量。6.2 常见集群状态检查命令# 查看槽位分配情况 redis-cli -p 7001 cluster nodes # 查看当前节点负责的槽位范围 redis-cli -p 7001 cluster slots # 查看集群各节点内存和连接数 redis-cli -p 7001 cluster info # 模拟键定位确认某个 key 应该落到哪个槽 redis-cli -p 7001 cluster keyslot user:10016.3 写入验证集群模式下普通 redis-cli 不自动计算槽位直接 SET key 有可能报MOVED错误。推荐使用集群模式连接redis-cli -c -p 7001然后执行127.0.0.1:7001 set user:1001 zhangsan 127.0.0.1:7001 get user:1001如果返回正确结果说明路由和节点间通信正常。这一步是整个集群验证里最基础、也最容易被忽略的环节。很多初学者用普通模式连 7001写入一个不属于 7001 槽位的 key看到 MOVED 错误就以为集群有问题其实是客户端没有启用集群模式。7. Redis 集群扩容与槽位迁移扩容是集群最核心的优势。当业务流量增长现有 3 主节点内存或 CPU 达到上限时可以动态加入新的节点而不需要停止服务。7.1 新增主节点先准备新节点配置文件端口比如 7007启动实例后加入集群redis-cli --cluster add-node 192.168.1.107:7007 192.168.1.101:7001前一个地址是新节点后一个地址是集群中任意一个已存在的节点。新节点加入后不会自动分配槽位此时它只是一个空主节点需要手动迁移槽位。7.2 重新分片redis-cli --cluster reshard 192.168.1.101:7001命令执行后Redis 会询问迁移多少个槽位、将槽位迁移到哪个节点 ID然后自动执行迁移过程。迁移期间客户端访问相关 key可能短暂出现ASK重定向集群模式下客户端会自动跟随对业务透明。7.3 新增从节点如果某个主节点需要扩容副本可以用集群中任意节点加入并指定主节点 IDredis-cli --cluster add-node 192.168.1.108:7008 192.168.1.101:7001 \ --cluster-slave --cluster-master-id 主节点ID主节点 ID 可以通过cluster nodes输出获取。8. Redis 集群 API 与客户端实践集群部署完成后业务接入方式也要相应调整。普通模式客户端无法自动处理节点重定向、故障转移后的连接切换必须使用支持集群协议的客户端。Java 生态最常用的是 Lettuce 和 RedissonPython 使用 redis-py-clusterGo 使用 go-redis。连接示例以 Python 和 Java 为主。8.1 Python 客户端连接集群from rediscluster import RedisCluster startup_nodes [ {host: 192.168.1.101, port: 7001}, {host: 192.168.1.102, port: 7002}, {host: 192.168.1.103, port: 7003}, ] rc RedisCluster( startup_nodesstartup_nodes, decode_responsesTrue, skip_full_coverage_checkTrue ) rc.set(user:1001, zhangsan) print(rc.get(user:1001))注意skip_full_coverage_checkTrue只适合槽位未完全覆盖或本地测试场景生产环境应保证所有槽位都有节点负责。8.2 Java 客户端连接集群import redis.clients.jedis.JedisCluster; import redis.clients.jedis.HostAndPort; import java.util.HashSet; import java.util.Set; public class ClusterDemo { public static void main(String[] args) { SetHostAndPort jedisClusterNodes new HashSet(); jedisClusterNodes.add(new HostAndPort(192.168.1.101, 7001)); jedisClusterNodes.add(new HostAndPort(192.168.1.102, 7002)); jedisClusterNodes.add(new HostAndPort(192.168.1.103, 7003)); JedisCluster jedisCluster new JedisCluster(jedisClusterNodes, 5000, 5000, 5); jedisCluster.set(user:1001, zhangsan); String value jedisCluster.get(user:1001); System.out.println(value); jedisCluster.close(); } }8.3 使用期注意事项使用 Redis 集群后部分命令行为会发生变化。比如MGET、MSET的多个 key 如果不在同一个槽位会直接报错。业务设计时要么按业务前缀确定 key 的归属让关联数据自然落在同一个槽要么改用 Pipeline 多次执行或客户端侧的串行调用。如果需要跨槽位原子操作应该使用 Hash Tag。凡是包含在{}中的字符串参与 CRC16 计算例如user:{1001}:name和user:{1001}:age这两个 key 会进入同一个槽位可以安全执行多 key 命令和 Lua 脚本。9. 资源占用与性能观察方法9.1 显存与内存占用Redis 集群主要观察内存占用不涉及显存。每个节点通过info memory查看自身内存redis-cli -p 7001 info memory重点关注used_memory、used_memory_rss、mem_fragmentation_ratio。如果mem_fragmentation_ratio明显大于 1.5需要考虑内存碎片整理或调整 maxmemory 策略。9.2 客户端连接耗时观察info stats中的total_commands_processed和instantaneous_ops_per_sec判断节点吞吐是否成为瓶颈redis-cli -p 7001 info stats | grep instantaneous_ops_per_sec9.3 批量任务与分片均衡集群模式下批量写入建议按业务流水号拆分每个任务只写入特定分片避免整个集群被一个大任务打满。如果出现某个分片内存明显高于其他分片说明存在数据倾斜应该调整 key 的命名规则或者迁移槽位来均衡。9.4 降低资源占用的思路启用maxmemory与合适的maxmemory-policy防止节点内存被占满。开启 AOF 时可以选择appendfsync everysec平衡性能与安全。避免使用包含大 value 的 key大 key 会导致节点内存不均、持久化耗时长、迁移 Slot 时阻塞网络。10. 常见问题与排查方法问题现象可能原因排查方式解决方案集群写入报 MOVED 错误使用普通 redis-cli 连接集群节点检查客户端是否启用集群模式使用 redis-cli -c 或支持集群协议的客户端集群创建后cluster_state:fail槽位未完全覆盖或节点超时检查cluster nodes和cluster slots重新执行reshard分配剩余槽位集群节点无法互相通信防火墙拦截群节点端口和总线端口检查节点间连通性开放每个 redis 实例的端口和端口 10000 的集群总线端口故障转移没有自动发生cluster-node-timeout过大或从节点不足查看节点日志和cluster info合理调小超时时间确保每个主节点有从节点增加节点后集群性能没有提升槽位没有重新分配查看新节点槽位数执行reshard均衡槽位批量写入大量失败流量过大导致节点响应超时查看节点slowlog和连接数增大cluster-node-timeout或优化批量任务分片策略MGET报错多个 key 不在同一个槽位使用cluster keyslot检查用 Hash Tag 或客户端拆分请求节点重启后数据不一致持久化配置不一致检查各节点 AOF/RDB 文件统一持久化策略优先使用 AOF11. Redis 集群与主从复制、哨兵模式对比维度主从复制哨兵模式Redis 集群数据分片无无16384 个哈希槽写扩展性不支持不支持支持读扩展性支持支持支持自动故障转移不支持支持支持数据容量扩展不支持不支持支持在线扩容部署节点数量最少 2 个最少 3 个哨兵加主从建议 6 个以上客户端复杂度低低高需支持集群协议运维复杂度低中高多 key 原子操作支持支持受槽位限制需 Hash Tag选择建议很简单几千 QPS、单机内存够用、能接受短时故障恢复主从复制加哨兵足够。单机内存达到上限、写入流量持续上涨、需要节点故障后系统自愈直接上 Redis 集群。数据量目前不大但业务增长快提前预判容量风险可以先用哨兵模式预留迁移到集群的代码兼容方案。12. 最佳实践与合规提醒12.1 工程化上线建议第一次搭建集群先用 6 个本地进程完整走一遍创建、写入、扩容、故障转移、缩容流程再上生产。每个节点使用独立配置文件和独立持久化目录避免实例间相互影响。生产环境不要只依赖 AOF 或 RDB 单一种类持久化建议同时开启并理解两者的恢复逻辑。监控脚本持续采集cluster_state、节点存活、槽位分布、内存使用故障发生时有日志可查。批量任务建议增加重试机制和超时控制避免某个节点临时不可用时任务整体失败。访问 Redis 集群的 IP 和端口要收敛在内网不要暴露到公网。即使有密码保护也不建议直接对外开放。集群节点扩展时优先选择低峰期执行迁移过程中持续观察网络和内存变化。12.2 安全与合规提醒Redis 在未配置认证和网络隔离环境下的风险极高。部署到服务器后必须设置强密码或开启 ACL 用户权限限制bind网段。集群模式下的节点间通信也有对应的认证配置需要一并处理。凡是涉及用户数据、业务敏感信息都应该在存储层做好权限控制和数据加密。本机或测试环境可以用简单的 bind 配置跑通流程生产环境安全策略必须单独评审。13. 总结与下一步主从复制不是 Redis 集群的替代方案而是构成 Redis 集群的地基。单机内存打满、写入流量上涨、自动故障转移要求变高时集群是绕不开的升级路径。从实操顺序上看建议第一步先在本地用 6 个进程把集群跑起来重点理解cluster info、cluster nodes和cluster keyslot三个命令第二步用redis-cli -c写入验证槽位分配第三步模拟一个主节点宕机观察从节点晋升和槽位重新分布第四步执行reshard完成一次扩容演练。这套流程走完Redis 集群的核心机制基本就掌握住了。最容易踩的坑是客户端模式不匹配。记住了能用redis-cli -c验证的是命令真正接入业务一定要用支持集群协议的客户端否则 MOVED 重定向和故障转移时的连接漂移就够排查半天。接下来的扩展方向包括集群各分片读写分离、多集群数据同步、基于 Redis 集群的分布式锁优化、跨数据中心容灾方案。先把基础集群跑通后面的每一步都会顺很多。