Redis Cluster集群搭建实战:3主3从配置、故障转移与运维避坑指南

发布时间:2026/10/12 21:47:36
Redis Cluster集群搭建实战:3主3从配置、故障转移与运维避坑指南
1. 从单机到集群为什么我们要折腾Redis ClusterRedis单机性能再强也扛不住数据量持续膨胀和单点故障带来的双重压力。我见过太多项目一开始用单实例跑得好好的业务量一上来内存告警、主从切换失败、写入阻塞全来了。Redis Cluster就是在这个背景下进入视野的——它把数据自动分片到多个节点每个分片再配从节点做冗余既解决了容量瓶颈又实现了故障自动转移。这个方案适合谁如果你手头有3台以上的服务器物理机或云主机都行业务数据量超过单机内存上限的60%或者对可用性有明确要求比如不能接受超过10秒的写入中断那集群模式就是绕不过去的选择。但要注意Redis Cluster不是银弹它有自己的脾气不支持多key跨槽操作、事务能力受限、运维复杂度直线上升。所以动手之前先把这些取舍想清楚。我这次搭建的环境是6个节点3主3从每台机器配置2核4GCentOS 7.9Redis版本6.2.7。为什么选这个版本6.x对集群的稳定性做了不少优化比如副本迁移的触发条件更合理而且社区资料足够丰富踩坑了也容易找到答案。下面我把整个搭建过程拆开揉碎从规划到验证每一步都附上我实际操作的命令和踩过的坑。2. 集群规划与前置准备别急着敲命令2.1 节点角色分配与端口规划集群搭建最忌讳的就是“边做边想”。我习惯先画一张表把每个节点的IP、端口、角色、数据目录、日志路径全部定死。这次用6台机器但为了模拟真实环境我在3台物理机上各起两个实例端口分别用7001和7002。为什么不在一台机器上起6个实例因为那样测不出网络分区和真实故障转移的效果而且生产环境绝不会把主从放在同一台物理机上。节点IP端口角色数据目录日志文件192.168.1.1017001Master/data/redis/7001/var/log/redis/7001.log192.168.1.1017002Slave/data/redis/7002/var/log/redis/7002.log192.168.1.1027003Master/data/redis/7003/var/log/redis/7003.log192.168.1.1027004Slave/data/redis/7004/var/log/redis/7004.log192.168.1.1037005Master/data/redis/7005/var/log/redis/7005.log192.168.1.1037006Slave/data/redis/7006/var/log/redis/7006.log注意生产环境务必把主从分散在不同物理机甚至不同机架上否则一台机器宕机可能同时带走主从两个节点集群直接不可用。2.2 系统参数调优这些坑我替你踩过了Redis对系统环境很敏感尤其是集群模式下节点间通信频繁几个内核参数不调好后面会出现各种诡异问题。我整理了一份必调清单# 1. 关闭透明大页避免Redis延迟抖动 echo never /sys/kernel/mm/transparent_hugepage/enabled # 2. 调整文件描述符限制集群连接数比单机高得多 ulimit -n 65535 # 3. 内核参数优化重点解决TIME_WAIT过多和端口复用 cat /etc/sysctl.conf EOF net.ipv4.tcp_tw_reuse 1 net.ipv4.tcp_fin_timeout 30 net.core.somaxconn 1024 vm.overcommit_memory 1 EOF sysctl -pvm.overcommit_memory 1这个参数特别关键。Redis在持久化时会fork子进程如果内存超额分配被禁止fork可能失败导致数据丢失。我遇到过凌晨三点告警说RDB保存失败查了半天就是这个参数没设。2.3 安装Redis与目录初始化安装本身没什么难度但目录结构要提前规划好。我习惯把二进制文件、配置文件、数据文件、日志文件全部分离方便后续维护和迁移。# 下载并编译 wget https://download.redis.io/releases/redis-6.2.7.tar.gz tar -zxvf redis-6.2.7.tar.gz cd redis-6.2.7 make make install PREFIX/usr/local/redis # 创建目录结构 mkdir -p /data/redis/{7001,7002,7003,7004,7005,7006} mkdir -p /var/log/redis mkdir -p /etc/redis # 复制配置文件模板 cp redis.conf /etc/redis/redis-7001.conf # 其余节点类似可以用脚本批量生成这里有个小技巧用sed批量替换配置文件里的端口、目录、日志路径比手动改6份文件快得多也不容易出错。for port in 7001 7002 7003 7004 7005 7006; do sed -e s/^port 6379/port ${port}/ \ -e s|^dir ./|dir /data/redis/${port}| \ -e s|^logfile \\|logfile /var/log/redis/${port}.log| \ -e s/^daemonize no/daemonize yes/ \ /etc/redis/redis-7001.conf /etc/redis/redis-${port}.conf done3. 核心配置详解集群模式的灵魂参数3.1 必须开启的集群开关Redis Cluster的配置项不多但每一个都影响生死。下面是我在redis.conf里必须修改的部分# 绑定地址生产环境不要用0.0.0.0按实际网卡填写 bind 192.168.1.101 # 端口每个节点不同 port 7001 # 开启集群模式这是总开关 cluster-enabled yes # 集群配置文件由Redis自动维护不要手动改 cluster-config-file nodes-7001.conf # 节点超时时间单位毫秒超过这个时间没响应就认为节点挂了 cluster-node-timeout 15000 # 开启AOF持久化集群模式建议开启 appendonly yes appendfilename appendonly-7001.aof # 后台运行 daemonize yes # 保护模式关闭否则外部无法连接 protected-mode nocluster-node-timeout这个值我设的是15000毫秒也就是15秒。设太短网络抖动就触发故障转移容易误判设太长真挂了要等很久才切换。根据我的经验同机房内网环境10-15秒比较合适跨机房的话要适当加大到30秒以上。3.2 集群总线端口容易被忽略的细节Redis Cluster节点之间通过一个额外的端口通信这个端口是服务端口10000。比如7001节点集群总线端口就是17001。如果服务器开了防火墙必须把这个端口也放行否则节点之间握手失败集群永远建不起来。# 开放服务端口和总线端口 firewall-cmd --permanent --add-port7001/tcp firewall-cmd --permanent --add-port17001/tcp firewall-cmd --reload我当初就是只开了7001没开17001cluster nodes命令一直显示节点状态是fail排查了两个小时才想起来总线端口这回事。这个坑你们千万别再踩。3.3 内存与淘汰策略的取舍集群模式下每个节点都是独立的内存空间淘汰策略要单独设置。我一般用allkeys-lru但有个前提必须确保从节点不参与淘汰。因为从节点默认是只读的如果它也开始淘汰数据会导致主从数据不一致。maxmemory 3gb maxmemory-policy allkeys-lru3GB是怎么算出来的机器总共4G内存系统和其他进程留1GRedis用3G再留一点给fork时的写时复制。如果设成3.5G持久化时很容易触发OOM。这个比例我试过很多次3G是相对安全的。4. 集群搭建实操从零到可用的完整流程4.1 启动所有节点并验证单机状态配置文件改好后先把6个节点全部拉起来。启动命令很简单但要注意用对配置文件。for port in 7001 7002 7003 7004 7005 7006; do /usr/local/redis/bin/redis-server /etc/redis/redis-${port}.conf done # 检查进程是否都在 ps -ef | grep redis-server | grep -v grep启动后别急着建集群先逐个连上去看看单机状态是否正常。用redis-cli -p 7001连上执行info server确认版本和端口都对。如果某个节点起不来多半是配置文件路径写错或者端口被占用看日志文件/var/log/redis/7001.log就能定位。4.2 使用redis-cli创建集群Redis 5.0之后redis-cli自带了集群创建工具比早期的ruby脚本方便太多。命令格式如下/usr/local/redis/bin/redis-cli --cluster create \ 192.168.1.101:7001 192.168.1.101:7002 \ 192.168.1.102:7003 192.168.1.102:7004 \ 192.168.1.103:7005 192.168.1.103:7006 \ --cluster-replicas 1--cluster-replicas 1表示每个主节点配一个从节点。执行后工具会自动分配槽位16384个槽平均分给3个主节点并指定主从关系。过程中会提示你确认配置输入yes回车即可。注意如果之前这些节点跑过集群模式nodes-*.conf文件里残留了旧信息创建会失败。解决办法是先停掉所有节点删除nodes-*.conf和appendonly.aof再重新启动。4.3 验证集群状态三个必查命令集群建好后第一件事是确认状态。我通常用三个命令交叉验证# 1. 查看集群整体信息 redis-cli -p 7001 cluster info # 关注 cluster_state:ok 和 cluster_slots_assigned:16384 # 2. 查看节点列表和主从关系 redis-cli -p 7001 cluster nodes # 确认每个主节点都有对应的从节点且角色正确 # 3. 检查槽位分配 redis-cli -p 7001 cluster slots # 确认16384个槽全部分配完毕没有遗漏cluster_state:ok是最终目标。如果显示fail通常是槽位没分完或者有节点失联。这时候用cluster nodes看哪个节点状态是fail或disconnected针对性排查网络和端口。4.4 数据读写测试验证分片和重定向集群模式下客户端连接任意节点都能读写但key会被路由到正确的节点。我用redis-cli -c-c表示跟随重定向来测试redis-cli -c -p 7001 127.0.0.1:7001 set user:1001 张三 - Redirected to slot [12345] located at 192.168.1.102:7003 OK 127.0.0.1:7001 get user:1001 - Redirected to slot [12345] located at 192.168.1.102:7003 张三看到Redirected说明分片和重定向机制正常工作。如果报CLUSTERDOWN错误说明集群状态异常回到上一步检查。5. 故障转移与扩缩容集群的日常运维5.1 模拟主节点宕机验证自动切换搭建完成只是开始真正的考验是故障发生时集群能不能自己扛住。我习惯手动模拟一次主节点宕机看看从节点能不能顺利顶上。# 找到7001主节点的进程号并杀掉 kill -9 $(ps -ef | grep redis-server | grep 7001 | awk {print $2}) # 观察集群状态变化每隔2秒执行一次 watch -n 2 redis-cli -p 7003 cluster nodes | grep master按照cluster-node-timeout 15000的设置大约15-20秒后7001的从节点7002会自动提升为主节点。用cluster nodes可以看到7002的角色从slave变成了master并且接管了7001原本负责的槽位。这个过程是全自动的不需要人工干预。实操心得故障转移期间客户端会短暂报错通常1-3秒建议在应用层做好重试机制。另外如果原主节点恢复后重新加入集群它会自动变成新主节点的从节点不会造成脑裂。5.2 在线扩容添加新节点业务增长后3主3从可能不够用需要加节点。扩容分两步先加节点再迁移槽位。# 启动新节点7007和7008配置参考前面的模板 # 将新节点加入集群作为主节点 redis-cli --cluster add-node 192.168.1.104:7007 192.168.1.101:7001 # 添加从节点指定它跟随哪个主节点 redis-cli --cluster add-node 192.168.1.104:7008 192.168.1.101:7001 \ --cluster-slave --cluster-master-id 7007的节点ID # 重新分片把部分槽位从旧节点迁移到7007 redis-cli --cluster reshard 192.168.1.101:7001 \ --cluster-from 源节点ID \ --cluster-to 7007节点ID \ --cluster-slots 1000 \ --cluster-yes--cluster-slots 1000表示迁移1000个槽位。迁移过程中集群仍然可用但涉及迁移槽位的key会有短暂阻塞。建议在业务低峰期操作并且一次不要迁移太多分批进行。5.3 缩容与节点下线缩容比扩容更危险因为要确保被下线节点上的数据全部迁移走。步骤必须严格按顺序来先用reshard把该节点的槽位全部迁走确认该节点不再负责任何槽位cluster nodes里该节点后面没有槽位范围用del-node命令移除节点# 迁移所有槽位到其他主节点 redis-cli --cluster reshard 192.168.1.101:7001 \ --cluster-from 待下线节点ID \ --cluster-to 目标节点ID \ --cluster-slots 该节点所有槽位数 \ --cluster-yes # 移除节点 redis-cli --cluster del-node 192.168.1.101:7001 待下线节点ID注意如果待下线的是主节点必须先把它负责的槽位全部迁走否则del-node会报错。从节点可以直接删但删之前确认它跟随的主节点不需要它做故障转移。6. 常见问题与排查技巧实录6.1 集群创建失败槽位分配卡住现象执行cluster create后卡在Waiting for the cluster to join最后报超时。排查思路九成是总线端口没通。在节点A上执行telnet 节点B的IP 总线端口如果不通检查防火墙和bind配置。另外如果节点之前跑过集群nodes.conf残留也会导致握手失败删掉重启即可。6.2 客户端报MOVED或ASK重定向现象应用连接集群后频繁收到MOVED错误。原因客户端没有开启集群模式或者没有正确处理重定向。大多数Redis客户端如Jedis、Lettuce都支持集群模式需要在连接配置里显式开启。如果用的是单机客户端连集群必然报错。解决以Jedis为例使用JedisCluster而不是Jedis并传入所有节点地址。客户端会自动维护槽位映射遇到重定向会内部处理。6.3 主从数据不一致现象主节点写入后从节点读不到最新数据。原因Redis主从复制是异步的写入主节点后立即读从节点可能还没同步过去。另外如果从节点设置了slave-read-only no并且被误写也会导致数据错乱。解决对一致性要求高的读操作强制走主节点用READONLY命令的反向操作即不发送READONLY。或者用WAIT命令阻塞等待指定数量的从节点确认。6.4 集群脑裂网络分区后的数据丢失现象网络恢复后发现部分写入的数据丢失了。原因网络分区期间主节点和从节点失联从节点被提升为新主节点。旧主节点恢复后发现自己变成了从节点会丢弃自己分区期间写入的数据从新主节点全量同步。缓解措施设置min-replicas-to-write和min-replicas-max-lag让主节点在从节点数量不足或延迟过大时拒绝写入。这样虽然牺牲了可用性但能减少数据丢失风险。min-replicas-to-write 1 min-replicas-max-lag 106.5 常见问题速查表问题现象可能原因快速排查命令解决方案cluster_state:fail槽位未分配完/节点失联cluster info、cluster nodes检查端口、重新分配槽位创建集群卡住总线端口不通telnet IP 17001开放防火墙、检查bindMOVED重定向客户端未开集群模式查看客户端配置改用集群客户端主从延迟大网络带宽不足/大keyinfo replication优化网络、拆分大key节点无法加入nodes.conf残留查看日志删除nodes.conf重启7. 生产环境运维建议血泪教训总结集群跑起来只是第一步长期稳定运行靠的是日常运维。我总结了几个必须坚持的习惯监控先行。至少监控三个指标集群状态cluster_state、节点连接数、主从延迟。我用Prometheus加Redis Exporter配合Grafana看板一旦cluster_state变成fail立即告警。别等业务反馈了才发现集群挂了。备份策略要独立。集群的RDB和AOF文件分散在各个节点上恢复时不能只拿一个节点的文件。我习惯每天凌晨在从节点上触发BGSAVE然后把RDB文件集中备份到对象存储。恢复时先按原拓扑启动节点再把RDB文件放回对应目录。版本升级要滚动进行。先升级所有从节点观察一天没问题再逐个升级主节点。升级主节点前手动触发一次故障转移让它变成从节点后再操作这样对业务几乎无感知。大key和热key是集群杀手。集群模式下大key会导致单个节点内存倾斜热key会让某个节点CPU跑满。我每周会用redis-cli --bigkeys扫一遍发现超过10MB的key立即拆分。热key的话在客户端加本地缓存或者用redis-cli --hotkeys定位。槽位迁移避开业务高峰。reshard操作会阻塞涉及槽位的读写虽然时间很短但高并发下可能引发雪崩。我一般选在凌晨2-4点做并且提前通知业务方。最后分享一个我实际踩过的坑有次扩容后忘了调整maxmemory新节点用了默认值不限制结果数据倾斜导致新节点内存爆了触发OOM Killer把Redis进程杀了。从那以后我在配置文件模板里强制加上maxmemory并且用Ansible批量下发确保每个节点配置一致。集群运维细节决定生死共勉。