资讯动态

Redis主从+哨兵高可用方案:从搭建到故障切换实战

发布时间:2026/10/26 5:01:29 来源:尧图企业网站定制
Redis 主从加哨兵这套组合放在今天依然是我见过最性价比的高可用方案之一。单机 Redis 扛不住读压力、挂了没人管这是很多中小项目在流量爬坡期最先撞上的墙。主从复制解决的是读扩展 数据冗余哨兵解决的是主节点挂了谁来顶——两件事拼在一起才算把高可用这三个字落到实处。这篇内容我打算把整套搭建过程从头到尾捋一遍包括我实际部署时踩过的坑、参数为什么这么配、故障切换到底是怎么触发的。适合手上有一两台 Linux 机器、想给 Redis 加一层保险的开发者也适合刚接触 Redis 高可用、看官方文档看得云里雾里的朋友。整套流程我会用三台机器来演示一主两从 三个哨兵命令、配置文件、验证步骤全部给全照着抄能跑通。1. 先把架构想清楚为什么是三台而不是两台动手之前有个问题必须先回答主从哨兵到底需要几台机器我见过不少人图省事一台机器上开三个 Redis 进程、三个哨兵进程跑是能跑起来但这就跟把鸡蛋全放一个篮子里还上了把锁一样——机器一宕全完。哨兵的核心价值是多数派投票投票的前提是哨兵本身得分散在不同故障域里否则投票毫无意义。1.1 主从复制和哨兵各自负责什么先把职责分清楚后面配置才不会乱。主从复制负责的是数据层面主节点master接收写请求把写命令通过复制流同步给从节点slave/replica从节点对外提供读服务。它的本质是一写多读 数据备份主节点挂了从节点数据还在但不会自动顶上来——这是关键很多人以为配了主从就有高可用了其实只是有了冗余。哨兵负责的是控制层面它是一组独立的进程不存数据只干三件事——监控、通知、故障转移。监控是指定期 ping 主从节点看活没活通知是指发现异常时通过发布订阅告诉其他哨兵和客户端故障转移是指确认主节点真的挂了之后从从节点里选一个出来当新主并让其余从节点改挂到新主上。这两层拼起来才是完整的高可用闭环。我习惯用一句话概括主从管数据哨兵管生死。理解了这个分工你就明白为什么哨兵的部署数量必须是奇数、且至少三个——因为要过半投票。1.2 三台机器的角色分配与端口规划我这次用的规划如下机器名用代称实际部署时换成你自己的 IP 即可机器IP 代称Redis 角色Redis 端口哨兵端口节点 A192.168.10.11Master637926379节点 B192.168.10.12Slave637926379节点 C192.168.10.13Slave637926379三台机器每台都跑一个 Redis 实例 一个哨兵实例。哨兵数量为 3满足奇数要求quorum判定客观下线的票数设为 2这样任意一台机器挂掉剩下两台哨兵仍能凑够多数派完成投票系统不会失去故障转移能力。如果只部署两个哨兵一旦挂一个就只剩一个永远凑不够 2 票等于白配。提示哨兵和 Redis 实例可以同机部署但生产环境建议哨兵至少有一个独立于 Redis 主节点的故障域。本文为了演示方便采用同机部署实际规划时把这点考虑进去。端口方面Redis 默认 6379哨兵默认 26379我都没改。如果你的环境里这些端口被占用改端口的同时记得同步改哨兵配置里的sentinel monitor行和防火墙规则否则哨兵连不上 Redis 会一直报sdown。2. 主从复制的落地从配置文件到全量同步主从复制的配置其实不复杂核心就一行replicaof。但配完能连上和配对了是两回事中间有几个参数和验证动作必须做到位否则你以为同步成功了实际可能只是连上了但没同步数据。2.1 主节点配置几个不能省的参数先在三台机器上装好 Redis版本建议 6.x 及以上本文命令以 6.2 为准5.x 也基本通用。主节点 A 的redis.conf我重点改这几处# 绑定地址按实际网卡改别图省事绑 0.0.0.0 bind 192.168.10.11 # 保护模式关掉绑定了具体 IP 后可关 protected-mode no # 端口 port 6379 # 后台运行 daemonize yes # 日志和数据目录按实际路径改 logfile /var/log/redis/redis.log dir /var/lib/redis # 主节点密码从节点和哨兵都要用 requirepass YourStrongPass123 # 从节点连接主节点时用的密码主节点上也要配供哨兵切换后使用 masterauth YourStrongPass123 # 开启 AOF主从场景下比 RDB 更稳 appendonly yes这里有两个点值得展开。第一requirepass和masterauth我建议设成一样虽然理论上可以不同但哨兵故障转移后新主会沿用配置密码不一致会导致从节点连不上新主切换直接失败。第二appendonly yes在主从场景下我强烈建议开——RDB 是定时快照主节点突然宕机可能丢最后一段时间的数据AOF 的持久化粒度更细配合主从能最大限度减少数据损失。改完启动主节点redis-server /etc/redis/redis.conf redis-cli -h 192.168.10.11 -p 6379 -a YourStrongPass123 ping返回PONG说明主节点起来了。这时候用redis-cli连上去执行INFO replication应该看到role:master且connected_slaves:0正常因为从节点还没配。2.2 从节点配置replicaof 那一行的门道从节点 B 和 C 的配置除了bind改成各自 IP其余和主节点基本一致额外加一行# 指定主节点格式replicaof masterip masterport replicaof 192.168.10.11 6379就这一行从节点启动后会自动去连主节点、发起全量同步PSYNC。但这里有个新手常踩的坑从节点默认是只读的replica-read-only yes这是对的别去改。有人为了让从节点也能写把它设成 no结果主从数据直接冲突同步流乱掉。从节点就该只读写请求统一走主节点。启动两个从节点后回到主节点执行redis-cli -h 192.168.10.11 -p 6379 -a YourStrongPass123 info replication正常应该看到类似role:master connected_slaves:2 slave0:ip192.168.10.12,port6379,stateonline,offset...,lag0 slave1:ip192.168.10.13,port6379,stateonline,offset...,lag0stateonline和lag0是关键前者说明复制链路通了后者说明从节点跟主节点几乎无延迟。如果state是wait_bgsave或send_bulk说明还在全量同步中数据量大的话要等一会儿如果一直是down八成是密码或网络问题。2.3 验证复制真的生效别只看状态要写数据状态显示 online 不代表数据真同步了我习惯做一次实打实的写入验证。在主节点写一个 keyredis-cli -h 192.168.10.11 -p 6379 -a YourStrongPass123 set test:repl hello然后分别到两个从节点读redis-cli -h 192.168.10.12 -p 6379 -a YourStrongPass123 get test:repl redis-cli -h 192.168.10.13 -p 6379 -a YourStrongPass123 get test:repl两个都返回hello复制链路才算真正打通。这一步别省我遇到过从节点状态显示 online 但实际因为masterauth配错、同步流被拒的情况光看状态会误判。注意从节点执行INFO replication应看到role:slave、master_link_status:up。如果master_link_status:down优先查主节点密码和masterauth是否一致。3. 哨兵配置三个进程如何达成共识主从跑通只是有了冗余真正让系统自愈的是哨兵。哨兵的配置文件叫sentinel.conf和redis.conf是两套东西别混。三台机器上的哨兵配置内容基本一致只有bind和sentinel myid自动生成不用手填不同。3.1 sentinel.conf 的最小可用配置每台机器上创建/etc/redis/sentinel.conf内容如下# 哨兵端口 port 26379 # 后台运行 daemonize yes # 日志 logfile /var/log/redis/sentinel.log # 监控主节点格式sentinel monitor master-name ip port quorum sentinel monitor mymaster 192.168.10.11 6379 2 # 主节点密码Redis 6 起哨兵也要认证 sentinel auth-pass mymaster YourStrongPass123 # 判定主观下线的时间单位毫秒默认 30 秒 sentinel down-after-milliseconds mymaster 30000 # 故障转移时最多同时有几个从节点同步新主 sentinel parallel-syncs mymaster 1 # 故障转移超时时间 sentinel failover-timeout mymaster 180000逐行说几个关键参数。sentinel monitor里的mymaster是集群名随便起但要全集群一致quorum 2表示至少 2 个哨兵认为主节点挂了才判定为客观下线ODOWN这是触发故障转移的门槛。down-after-milliseconds 30000是主观下线SDOWN的判定时间——单个哨兵 ping 主节点超过 30 秒没响应就认为它可能挂了但还只是主观判断要凑够 quorum 票才升级为客观下线。parallel-syncs 1这个参数容易被忽略。故障转移后新主会同时接受多个从节点同步设成 1 表示一次只让一个从节点同步其余排队。这样做的目的是避免新主被多个全量同步同时压垮——全量同步会 fork 子进程生成 RDB很吃 CPU 和内存串行化能保护新主。数据量大的集群这个值保持 1 最稳。3.2 哨兵启动与互相发现的机制三台机器分别启动哨兵redis-sentinel /etc/redis/sentinel.conf # 或者用 redis-server 启动效果一样 redis-server /etc/redis/sentinel.conf --sentinel启动后连上任意一个哨兵redis-cli -h 192.168.10.11 -p 26379 info sentinel应该看到sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 master0:namemymaster,statusok,address192.168.10.11:6379,slaves2,sentinels3重点看sentinels3和slaves2。哨兵之间是通过主节点的发布订阅频道__sentinel__:hello互相发现的——每个哨兵启动后会往这个频道发消息其他哨兵订阅到就知道哦还有同行在然后互相记录到自己的哨兵列表里。所以哨兵不需要在配置里写彼此的地址只要都监控同一个主节点它们会自动组网。这个机制很多人不知道以为要手动配哨兵列表其实不用。如果sentinels显示小于 3说明哨兵之间还没互相发现等几秒再查或者检查三台机器的 26379 端口是否互通、密码是否一致。3.3 用 kill 模拟主节点宕机看切换全过程配置完不验证等于没配。我习惯直接 kill 掉主节点进程来模拟真实宕机# 在主节点 A 上 redis-cli -h 192.168.10.11 -p 6379 -a YourStrongPass123 shutdown nosave然后盯着任意一个哨兵的日志tail -f /var/log/redis/sentinel.log你会依次看到这些事件时间戳省略sdown master mymaster 192.168.10.11 6379 # 主观下线 odown master mymaster 192.168.10.11 6379 #quorum 2/2 # 客观下线 try-failover master mymaster 192.168.10.11 6379 # 开始故障转移 vote-for-leader ... # 选举领头哨兵 elected-leader master mymaster 192.168.10.11 6379 failover-state-select-slave master mymaster ... # 选新主 selected-slave slave 192.168.10.12:6379 ... # 选中 B 当新主 failover-state-send-slaveof-noone slave ... # 让 B 升主 failover-state-wait-promotion slave ... # 等待 B 晋升 promoted-slave slave 192.168.10.12:6379 ... # B 晋升成功 failover-state-reconf-slaves master ... # 让 C 改挂新主 slave-reconf-sent slave 192.168.10.13:6379 ... # 通知 C slave-reconf-inprog slave 192.168.10.13:6379 ... slave-reconf-done slave 192.168.10.13:6379 ... failover-end master mymaster 192.168.10.12 6379 # 切换完成 switch-master mymaster 192.168.10.11 6379 192.168.10.12 6379 # 主节点地址变更这一串日志就是完整的故障转移链路。核心逻辑是先 SDOWN凑够 quorum 变 ODOWN然后哨兵之间选一个领头leader来执行转移leader 从从节点里挑一个数据最新的比较offset升为主再让其余从节点改挂新主。整个过程默认在几十秒内完成取决于down-after-milliseconds和网络状况。切换完成后用redis-cli连 192.168.10.12 执行INFO replication会看到它已经是role:master且connected_slaves:1C 挂过来了。这时候原来的主节点 A 如果重启哨兵会自动把它降级为从节点挂到新主 B 上——这个自动降级是哨兵很贴心的设计不用手动干预。4. 客户端怎么找到新主别把 IP 写死故障转移完成后有个现实问题客户端原来连的是 A现在主变成 B 了客户端怎么知道如果客户端配置里写死了192.168.10.11:6379那切换对它来说等于没发生写请求全打到已经降级的 A 上直接报错。这是主从哨兵方案里最容易被忽略的一环。4.1 哨兵感知模式客户端要主动问哨兵正确的做法是客户端连哨兵而不是直连 Redis。以常见的 Java 客户端为例配置里给的是哨兵地址列表// 伪代码示意具体 API 按客户端版本调整 SetString sentinels new HashSet(); sentinels.add(192.168.10.11:26379); sentinels.add(192.168.10.12:26379); sentinels.add(192.168.10.13:26379); JedisSentinelPool pool new JedisSentinelPool( mymaster, // 集群名和 sentinel monitor 里一致 sentinels, new JedisPoolConfig(), YourStrongPass123 // 哨兵密码 );客户端启动时会问哨兵mymaster 现在的主是谁哨兵返回当前主地址客户端再连过去。故障转移后哨兵会通过发布订阅通知客户端主变了客户端自动重连新主。整个过程对业务代码透明业务只管从连接池拿连接。这里有个细节哨兵地址列表要写全别只写一个。如果只写一个哨兵地址那个哨兵挂了客户端就找不到集群了。三个都写上客户端会轮询容错性最好。4.2 密码认证的两层坑Redis 6 之后哨兵也支持认证这里有两层密码容易搞混一层是客户端连哨兵的密码如果哨兵配了requirepass另一层是哨兵连 Redis的密码sentinel auth-pass。我见过有人只配了后者客户端连哨兵时没带密码被拒排查半天。如果你给哨兵也加了requirepass生产环境建议加那客户端连接池初始化时要把哨兵密码传进去。不同客户端 API 不一样有的叫sentinelPassword有的直接在连接参数里带。配之前先看客户端文档别想当然。提示哨兵配置里如果加了requirepass记得三台机器都加且密码一致。哨兵之间通信也要认证不一致会导致互相发现失败sentinels数量上不去。4.3 切换期间的写失败怎么兜底即便客户端用了哨兵模式故障转移那几十秒内写请求还是会失败——因为新主还没选出来或者客户端还没收到通知。这段脑裂窗口是客观存在的任何主从方案都躲不掉。我的处理经验是业务层要有重试。具体做法是给写操作包一层重试逻辑捕获连接异常后等 1~2 秒重试最多重试 3 次。因为哨兵的切换通常在 30 秒内完成down-after-milliseconds设 30 秒的话重试窗口覆盖得住。如果业务对写一致性要求极高那得考虑更重的方案但绝大多数场景下重试 哨兵已经够用。另外提醒一句切换期间如果有客户端还在往旧主写旧主还没被降级会产生数据不一致。哨兵通过min-replicas-to-write这类参数能在一定程度上缓解但根治要靠客户端及时感知。所以客户端一定要用哨兵模式别直连。5. 那些文档里不写、但实际会咬人的细节配置跑通只是开始真正让这套集群在生产里稳住靠的是一堆细节。下面这几条都是我在实际部署里踩出来的官方文档要么没提要么一笔带过。5.1 时间同步哨兵误判的隐形杀手哨兵的down-after-milliseconds是基于本地时间算的如果三台机器时间不同步可能出现一台哨兵认为已经过了 30 秒另一台认为才过了 10 秒导致 SDOWN 判定不一致故障转移被拖延甚至误触发。部署前务必确认三台机器开了时间同步这是最容易被忽略、又最影响稳定性的基础项。检查方法很简单三台机器分别执行date看时间差是否在秒级以内。如果差得多先把时间同步配好再谈别的。我见过一次线上切换慢排查半天最后发现是某台机器时间漂了十几分钟哨兵日志时间戳全乱定位极其痛苦。5.2 内存与 maxmemory别让主节点被 OOM 拖死主从架构下主节点内存压力最大因为它要处理所有写请求还要维护复制缓冲区。如果没设maxmemory主节点内存涨到系统上限会被 OOM killer 干掉触发一次本可避免的故障转移。我的建议是给主节点设maxmemory并配好淘汰策略maxmemory 4gb maxmemory-policy allkeys-lruallkeys-lru适合纯缓存场景如果数据不能随便淘汰用noeviction并配合监控告警让运维提前介入。另外复制缓冲区repl-backlog-size默认 1MB写流量大的集群建议调到 64MB 以上否则从节点短暂断连后可能触发全量同步很吃资源。5.3 哨兵数量与 quorum 的搭配陷阱前面说哨兵要奇数、至少三个但 quorum 怎么设也有讲究。quorum 是判定客观下线需要的票数它和哨兵总数是两个概念。三个哨兵时 quorum 设 2 是合理的但如果哨兵扩到 5 个quorum 还是 2那只要 2 个哨兵认为主挂了就触发转移容错性反而下降可能因为网络抖动误判。一般原则是quorum 设为哨兵总数的一半加一3 个设 25 个设 3这样既保证能触发又不会太敏感。还有个隐藏规则故障转移要真正执行除了满足 quorum还需要多数派哨兵存活majority。3 个哨兵时多数派是 2所以挂 1 个还能切换如果挂 2 个只剩 1 个即便这 1 个认为主挂了也凑不够多数派切换不会发生。这就是为什么哨兵数量必须是奇数——偶数在平票时无法形成多数派。5.4 日志和监控切换发生了你得知道哨兵的日志默认只记关键事件但生产环境我建议把日志级别调到notice甚至debug排查期并接入日志收集。更重要的是监控switch-master事件——这个事件一出现就说明发生了主从切换必须有人知道。可以写个简单的脚本订阅哨兵的发布订阅频道redis-cli -h 192.168.10.11 -p 26379 -a YourStrongPass123 \ psubscribe switch-master sdown odown一旦有切换终端会实时打印出来。生产环境把这个接到告警系统切换即告警别等业务报错了才发现主早就换了。6. 收尾前再聊两句实操体会整套搭下来主从哨兵的门槛其实不高配置文件加起来不到五十行难的是把每个参数背后的为什么想明白。我最初配的时候也是照抄教程结果第一次真实故障时切换没成功翻日志才发现是masterauth和requirepass不一致从节点连不上新主。从那以后我养成了一个习惯每次配完一定手动 kill 一次主节点完整走一遍切换流程把日志从头看到尾确认每个事件都符合预期才算这套集群真的可用。还有个心得是关于够用就好。主从哨兵不是银弹它解决的是单点故障和读扩展但写能力还是单主数据量特别大或者写 QPS 极高时得上 Cluster 分片方案。选型时先想清楚自己的瓶颈在哪——是读扛不住、还是怕主挂了、还是写也扛不住对症下药比盲目上复杂方案强。对大多数中小项目来说一主两从加三哨兵配合客户端哨兵模式和业务重试已经能覆盖 90% 的高可用需求了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑