Redis哨兵模式全解析:高可用架构原理与故障转移实操 1. 为什么要折腾哨兵模式先说个我自己的经历。前几年维护过一套电商系统Redis 存的是商品缓存、登录态、限流计数这些数据。一开始用的是单机 Redis跑了大半年没出过事我就没太当回事。结果有一次机房物理机掉电Redis 直接没了等机器重启再去手动拉起服务前后折腾了二十多分钟那二十分钟线上所有依赖缓存的接口全部超时数据库差点被打挂。当时我就意识到单机 Redis 做得再好也挡不住一台机器挂掉这种不可抗力。后来我搭建了主从复制架构主节点负责写从节点负责读本来以为这下稳了。结果过了一周主节点因为内存碎片问题挂了一次我还在睡梦中等收到告警起来手动执行SLAVEOF切换已经过去了十几分钟。这次经历让我彻底明白主从复制只解决了数据冗余问题没有解决“人”的问题——主节点挂了必须要有人去操作才能恢复服务这个周期性维护成本实在太要命。于是我去研究了 Redis Sentinel哨兵模式。简单说哨兵就是一群独立运行的小守护进程专门盯着 Redis 主从节点看如果主节点失联了哨兵们会商量一下然后从多个从节点中自动挑一个提升为新的主节点整个过程几乎不需要人工参与几十秒内就能完成故障转移。这种感觉就像家里请了一个不睡觉的保安水电出问题他能自动处理不需要你半夜爬起来找师傅。这篇文章从头讲一遍哨兵模式的完整搭建流程覆盖架构设计、配置参数、故障演练、常见问题排查包括一些我实际踩过、查了很久资料才搞明白的隐蔽坑。不论你是运维、后端开发还是自己在折腾服务器的个人开发者照着这篇文章走一遍基本可以应对生产环境中绝大多数主备切换场景。文章里涉及的操作都在 Linux 环境下验证过Redis 版本是 5.0 以上但大部分配置思想对低版本同样适用。2. 哨兵模式的整体设计与核心原理2.1 哨兵到底在干啥要理解哨兵的配置得先理清它的职责。Redis 官方文档中描述 Sentinel 有四大功能监控Monitoring、自动故障转移Automatic failover、通知Notification、配置提供者Configuration provider。监控好理解哨兵每秒发一次 PING 给所有主节点和从节点如果某个节点在down-after-milliseconds规定的时间内没有响应哨兵就认为这个节点主观下线sdownsubjective down。但注意一个哨兵说了不算因为可能是网络抖动或哨兵自己的问题所以需要多个哨兵互相确认。当多个哨兵都认为主节点挂了并且数量达到quorum设定的阈值这时主节点才会被标记为客观下线odownobjective down然后触发故障转移流程。这个设计逻辑很像我们工作中的“举手表决”——不能只听一个人说“不行了”要让多个独立的观察者都确认才算数。这样做能有效避免单点哨兵误判导致频繁切换、主备脑裂等问题。故障转移的过程可以拆成这几步领先的哨兵节点Leader从所有健康的从节点里挑一个通过SLAVEOF NO ONE命令把它提升为主节点。其他从节点收到新配置后自动去同步新主节点的数据。哨兵们更新内存中的主节点地址并向客户端发布新的连接信息。如果原来的主节点恢复了它会发现自己的角色变了自动降级为新主节点的从节点老老实实去同步数据。哨兵架构还存在一个“配置提供者”的功能经常被忽略但非常实用客户端连接 Redis 时可以直接问哨兵“谁是当前的主节点”哨兵会告诉你准确地址。这样应用层就不用硬编码主节点 IP切换后也能自动跟上新主节点实现业务无感。像 Java 生态中的 Lettuce、Spring Redis 客户端都支持通过哨兵节点获取主节点地址。2.2 三个哨兵还是一堆哨兵部署哨兵时最大的疑问往往是到底部署几个哨兵只部署一个行不行我在测试环境试过只部署一个哨兵结论是主从复制逻辑没问题主节点挂了也能切换但这不是高可用而是把单点从 Redis 挪到了哨兵上。一旦唯一的哨兵宕机Redis 集群就失去了故障转移触发能力和没有哨兵没有本质区别。所以生产环境至少三个哨兵。那为什么是“三”核心原因是哨兵判断客观下线需要投票如果部署两个哨兵其中一个挂了剩下一个无论如何都凑不够票数quorum 上限要小于等于哨兵总数故障转移就无法触发。部署三个哨兵quorum 配置为 2即使一个哨兵挂了另外两个还能正常协商完成转移。这也是为什么大家常说“哨兵部署必须是奇数”——本质是让“少数服从多数”的选举机制始终能得出唯一结论避免平票。我在测试时曾经把三个哨兵跑在同一台机器上这倒是能跑通但注意生产环境一定要把哨兵分布在不同的物理机或云主机上。如果在同一台机器上机器一挂三个哨兵跟着一起挂高可用同样无从谈起。这是典型的“机房级可用性”思维跨机器、跨机架、甚至跨可用区部署。2.3 主从复制与哨兵的关系经常有人问配置哨兵之前是不是一定要配好主从复制答案是是的。哨兵本质是在现有主从架构之上做“保姆”和“裁判”它本身不负责数据同步同步是 Redis 主从复制机制自己完成的。所以搭建哨兵模式的完整路径是先有主从架构再引入哨兵做监控和自动切换。主从复制这里简单提一句在从节点的redis.conf中配置replicaof 主节点IP 主节点端口Redis 5.0 之前叫slaveof从节点启动后会自动同步主节点的全部数据。如果需要从节点只读配置slave-read-only yes即可避免意外写入导致数据不一致。另外注意主从复制中的数据同步是全量加增量配合的首次同步是 RDB 快照全量同步后续通过命令传播做增量同步。网络中断或主节点重启后会尝试部分重同步partial resynchronization实在不行再全量同步。这块机制对理解切换后数据是否丢失很重要——故障转移期间未同步到从节点的少量数据可能确实会丢失这也是 CAP 理论中 AP 模式的取舍业务上要提前做补偿设计。3. 环境准备与基础配置3.1 拓扑规划我这次实操的规划如下一共三台 Linux 虚拟机均为 CentOS 7.9Redis 版本 6.0.16主机名IP节点角色端口redis-master192.168.56.101Redis 主节点6379redis-slave-1192.168.56.102Redis 从节点 16379redis-slave-2192.168.56.103Redis 从节点 26379sentinel-1192.168.56.101哨兵 126379sentinel-2192.168.56.102哨兵 226379sentinel-3192.168.56.103哨兵 326379三个哨兵分别和三个 Redis 节点共置部署。这样部署是为了省机器同时保证了“三个哨兵不在一台机器上”的基本要求。生产环境如果你的预算充裕更推荐哨兵独立部署在单独的小规格机器上因为哨兵本身资源开销很小空闲时内存占用不到 20MB独立部署可以把 Redis 节点的故障对哨兵的影响降到最低。注意本文中的地址是实验环境专用不涉及任何实际生产公网信息你搭建时替换成自己的内网 IP 即可。3.2 安装 Redis 与基础主从配置三台机器都安装 Redis 6.0.16。我习惯用源码编译安装因为可控性更强能选择安装路径也便于后续维护。下面以redis-master为例三台机器操作一致。# 安装编译依赖 yum install -y gcc gcc-c make tcl # 下载并解压也可以上传本地安装包 wget https://download.redis.io/releases/redis-6.0.16.tar.gz tar xzf redis-6.0.16.tar.gz cd redis-6.0.16 # 编译安装 make make installmake install默认会把可执行文件放到/usr/local/bin包括redis-server、redis-cli、redis-sentinel、redis-check-rdb等工具。以我经验在 CentOS 7 上编译 Redis 6.0 时最容易踩的坑是 gcc 版本过低。默认yum install gcc装的是 4.8.5编译 Redis 6.0 会报错提示不兼容。需要先安装高版本 GCCyum install -y centos-release-scl yum install -y devtoolset-9-gcc devtoolset-9-gcc-c scl enable devtoolset-9 bash然后在当前终端重新编译即可。这个问题我之前遇到过两次每次都是卡在编译阶段后来学聪明了第一件事就是先确认gcc --version。编译完成后在主节点redis-master上创建一个/etc/redis目录存放配置文件便于集中管理mkdir -p /etc/redis cp /usr/local/redis-6.0.16/redis.conf /etc/redis/redis.conf主节点配置中必须修改的关键项# 允许后台启动不然关闭终端后 Redis 就没了 daemonize yes # 绑定内网网卡 IP默认只监听 127.0.0.1 bind 0.0.0.0 # 关闭保护模式否则外部无法连接 protected-mode no # 数据持久化路径 dir /var/lib/redis # 可选的生产环境务必设置访问密码 # requirepass your-strong-password # 可选设置从节点访问主节点的认证密码 # masterauth your-strong-password # 日志文件方便排错 logfile /var/log/redis/redis-server.log注意protected-mode no仅在可信内网环境使用。如果 Redis 暴露到了公网一定要设置强密码并开启防火墙白名单。公网裸奔的 Redis 被扫到漏洞后可能直接被写入定时任务做挖矿这种事业界已经多次报道了不要心存侥幸。从节点的配置和主节点有两处区别需要设置replicaof指向主节点同时一般开启只读模式# 从节点 redis.conf 中额外加上这一行 replicaof 192.168.56.101 6379 # 只读模式 slave-read-only yes两台从节点配置完成后依次启动三个节点的 Redisredis-server /etc/redis/redis.conf在主节点上查看复制关系redis-cli -h 192.168.56.101 -p 6379 info replication输出类似# Replication role:master connected_slaves:2 slave0:ip192.168.56.102,port6379,stateonline,offset123456,lag0 slave1:ip192.168.56.103,port6379,stateonline,offset123456,lag0看到两个stateonline说明主从复制关系已经建立。这时候可以自己写几条测试数据在从节点上keys *确认数据同步正常。小坑提醒早期 Redis 版本中slave-read-only和replicaof是分开配置的Redis 5.0 之后都统一用replica相关命令了但老配置项仍然兼容可用。如果你是在 Redis 4.0 以下版本操作注意命令是slaveof而不是replicaof。3.3 哨兵配置文件逐项解读哨兵的配置文件和 Redis 主配置文件是同一套语法体系。在每台机器上创建/etc/redis/sentinel.conf内容如下各机器只有sentinel announce-ip和sentinel monitor中的本机 IP 不同其他一致# 哨兵监听端口 port 26379 # 后台运行 daemonize yes # 日志 logfile /var/log/redis/sentinel.log # 持久化文件记录哨兵状态不用手动修改 dir /var/lib/redis-sentinel # 监控主节点指定主节点别名、IP、端口、投票法定数 sentinel monitor mymaster 192.168.56.101 6379 2 # 主节点响应超时时间单位毫秒 sentinel down-after-milliseconds mymaster 5000 # 故障转移时最多几个从节点同时同步新主节点 sentinel parallel-syncs mymaster 1 # 故障转移超时时间单位毫秒 sentinel failover-timeout mymaster 15000 # 若主节点配置了密码这里必须设置否则哨兵无法完成身份验证 # sentinel auth-pass mymaster your-strong-password # 哨兵之间互相发现的广播地址多网卡环境下务必配置 sentinel announce-ip 192.168.56.101 sentinel announce-port 26379逐个解释关键参数sentinel monitor mymaster 192.168.56.101 6379 2是哨兵配置中最核心的一行。mymaster是为主节点起的别名可以随便取但要保持各哨兵一致后面的 IP 和端口必须是主节点真实地址最后的数字 2 就是quorum意思是“至少需要 2 个哨兵同意才判定主节点客观下线并触发切换”。在 3 个哨兵的架构中quorum 设为 2 是最常见配置既不会因为单节点误判而切换也不会因为票数不够而无法切换。down-after-milliseconds控制判断主观下线的超时时间单位毫秒。这里我设的 5000 毫秒也就是主节点 5 秒没响应单个哨兵先标记 sdown。真实生产环境建议根据网络状况调整内网可以设短一点3~5 秒跨机房网络建议 10 秒以上避免网络抖动导致频繁切换。我见过有人把这个值设成 3000结果机房偶尔出现 100ms 级别的网络毛刺就触发切换业务连接池白抖了几次。parallel-syncs表示故障转移后同时允许几个从节点去新主节点做全量同步。设置为 1 的意思是“一个一个来”避免多个从节点同时全量复制把新主节点的内存和带宽瞬间打满。如果从节点数量多这个值必须保持为 1 或 2否则新主会有较大压力。failover-timeout是故障转移总超时从开始切换到完成的时间窗口。15 秒对于大多数场景已经足够包含哨兵选举、从节点提升、其他从节点重新指向新主节点这几个步骤。如果超过这个时间还没完成哨兵会重新尝试直到最终一致。sentinel announce-ip和sentinel announce-port是给哨兵做地址广播用的。当哨兵部署在 NAT 环境或有多块网卡时如果不配置哨兵之间可能用错误的内网 IP 互相通信导致彼此发现不了。这个参数属于“平时用不到、踩坑时救命”的类型。我这次因为每台机器有两块网卡不配置就无法正常通讯所以特意加上。3.4 启动哨兵并验证发现机制三台机器都配置好sentinel.conf后分别启动redis-sentinel /etc/redis/sentinel.conf或者用redis-server以哨兵模式启动也行效果一样redis-server /etc/redis/sentinel.conf --sentinel启动后用哨兵客户端连上去查看状态redis-cli -p 26379 info sentinel正常情况下输出类似# Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_maxlen:128 sentinel_simulate_failure_flags:0 master0:namemymaster,statusok,address192.168.56.101:6379,slaves2,sentinels3重点关注statusok、slaves2、sentinels3。如果sentinels小于 3说明哨兵之间没有互相发现。此时先检查防火墙是否放行 26379 端口再看sentinel announce-ip是否配置正确。用命令查看哨兵视角下的完整拓扑redis-cli -p 26379 sentinel master mymaster redis-cli -p 26379 sentinel slaves mymaster redis-cli -p 26379 sentinel sentinels mymaster这些命令输出中包含了每个被监控节点的 IP、端口、状态、最后响应时间等信息排查故障转移问题时非常好用建议养成习惯每次切换演练前先跑一遍。4. 实操主节点宕机与自动故障转移全记录4.1 写入测试数据与观察正常状态为了避免演练时干瞪眼我提前在两个从节点写入了一些模拟数据。例如在主节点执行redis-cli -p 6379 set user:1001 zhangsan redis-cli -p 6379 set user:1002 lisi redis-cli -p 6379 set counter:order:202501 25000然后依次在两个从节点上执行keys *确认数据都同步过去了。这一步很重要因为后面故障转移完成后要验证“老数据还在新数据是否丢失”才能评估切换效果。同时开启哨兵日志观察tail -f /var/log/redis/sentinel.log这个日志是整个故障转移过程的“黑匣子”每一步切换都有记录包括谁发起的选举、谁被提升为主节点、各从节点的重新配置状态。玩转哨兵的关键能力之一就是能看懂这些日志并还原整个事故过程。4.2 模拟主节点故障演练操作直接在主节点机器上杀掉 Redis 进程模拟“物理宕机”中最核心的故障形态。redis-cli -p 6379 shutdown nosave这里用shutdown nosave是为了快速让进程退出模拟突然断电时“数据还没持久化”的极端情景。如果用kill -9效果类似Redis 没有机会做优雅退出处理。杀掉主节点后立刻回看哨兵日志。哨兵 1与主节点同机的日志中会出现类似下面的记录11944:X 01 Jan 2025 14:23:31.176 # sdown master mymaster 192.168.56.101 6379 11944:X 01 Jan 2025 14:23:35.447 # odown master mymaster 192.168.56.101 6379 #quorum 2/2 11944:X 01 Jan 2025 14:23:35.447 # new-epoch 1 11944:X 01 Jan 2025 14:23:35.447 # try-failover master mymaster 192.168.56.101 6379 11944:X 01 Jan 2025 14:23:35.451 # vote-for-leader 0d3c8d1e4f9a2b7e6c0a5f3d9e2f1c0b8a7d4e6f 1 11944:X 01 Jan 2025 14:23:35.458 # elected-leader master mymaster 192.168.56.101 6379 11944:X 01 Jan 2025 14:23:35.458 # failover-state-select-slave master mymaster 192.168.56.101 6379 11944:X 01 Jan 2025 14:23:35.470 # selected-slave slave 192.168.56.102:6379 192.168.56.102 6379 11944:X 01 Jan 2025 14:23:35.470 # failover-state-send-slaveof-noone slave 192.168.56.102:6379 11944:X 01 Jan 2025 14:23:35.472 # failover-state-wait-promote slave 192.168.56.102:6379 11944:X 01 Jan 2025 14:23:35.525 # promoted-slave slave 192.168.56.102:6379 11944:X 01 Jan 2025 14:23:35.525 # failover-state-reconf-slaves master mymaster 192.168.56.101 6379 11944:X 01 Jan 2025 14:23:36.463 # slave-reconf-sent slave 192.168.56.103:6379 11944:X 01 Jan 2025 14:23:37.780 # slave-reconf-inprog slave 192.168.56.103:6379 11944:X 01 Jan 2025 14:23:38.200 # slave-reconf-done slave 192.168.56.103:6379 11944:X 01 Jan 2025 14:23:38.240 # failover-end master mymaster 192.168.56.101 6379 11944:X 01 Jan 2025 14:23:38.240 # switch-master mymaster 192.168.56.101 6379 192.168.56.102 6379 11944:X 01 Jan 2025 14:23:38.240 # sdown slave 192.168.56.101:6379这段日志非常典型完整记录了故障转移流程。我来解读一下关键行sdown哨兵 1 主观判断主节点不可达。odown ... quorum 2/2三个哨兵中至少两个达成一致主节点被客观判定下线。注意这里的 2/2 不一定是两个哨兵在线确认而是满足 quorum 的票数。try-failover进入故障转移流程。vote-for-leader推选哨兵 Leader负责执行本次切换。日志中那串长 ID 是哨兵运行 ID不是节点 ID。elected-leader本哨兵被选为执行者。selected-slave从候选从节点中选定了192.168.56.102:6379作为新主节点。这里选中的逻辑不是随机选最早的从节点而是综合考虑优先级slave-priority默认 100数值越小优先级越高、复制偏移量和运行 ID。promoted-slave新主节点提升成功。slave-reconf-sent/slave-reconf-inprog/slave-reconf-done另一个从节点192.168.56.103被重新配置为指向新主节点并完成同步。switch-master哨兵已经把“当前主节点”的视角切换为192.168.56.102:6379至此故障转移成功。整个过程耗时约 7 秒从主节点失联到新主节点对外提供服务用了不到 10 秒相比我手动切换时的十几分钟这个效率的提升是质变。4.3 故障转移后的数据验证与恢复测试切换完成后我立刻去验证数据。用客户端连接新主节点redis-cli -h 192.168.56.102 -p 6379 info replication输出中role:master并且connected_slaves:1那个从节点是192.168.56.103。再去查询演练前写入的user:1001、user:1002、counter:order:202501几个 key都存在。接下来测试只读从节点192.168.56.103是否正常同步新主的数据redis-cli -h 192.168.56.103 -p 6379 keys *结果证明同步正常。这说明哨兵切换不只是完成了“换主”这个动作还顺带着把整个主从拓扑重新收敛了数据一致性在绝大多数场景下得到保障。然后是大家问得最多的一个场景旧主节点恢复了会发生什么我手动拉起原来挂掉的 Redis 进程redis-server /etc/redis/redis.conf启动后第一时间查看它的角色和复制状态redis-cli -h 192.168.56.101 -p 6379 info replication输出建议重点关注这两行role:slave master_host:192.168.56.102也就是说原主节点在重新上线后检测到自己已经不再是主节点自动降级为从节点并且把新主节点192.168.56.102设为自己的 master。这个行为是哨兵通过发布订阅机制和配置文件重写功能实现的——哨兵会把监控状态同步给所有节点原主节点醒来后会读取到新配置从而自动完成角色转换。整个过程不需要人工介入这也是哨兵模式“真正高可用”的体现。经验之谈旧主节点降级后我在它上面写的任何数据都会被复制冲掉因为它现在是一个从节点必须严格跟随新主的数据。所以故障转移完成后千万不要在旧主上继续写业务数据否则要么写入报错只读模式要么直接被新主的数据覆盖容易引发“数据倒流”的误解。4.4 哨兵进程自身故障的影响顺便也做了一个测试杀掉其中一个哨兵进程观察集群是否还能正常切换。我把redis-sentinel进程 kill 掉一个后再用命令查看剩余两个哨兵的状态。两个哨兵之间依然维持正常通信因为另外两个哨兵仍然存活并组成多数。这时如果主节点故障剩下的两个哨兵可以凑够 quorum2仍然能正常执行故障转移。不过要注意如果 quorum 也设成 2而恰好有两台哨兵在同一时间内故障那就无法触发转移了。这也是为什么生产环境建议“哨兵数量为奇数且 quorum 等于 (N1)/2 向上取整”的原因。哨兵进程本身一般不会崩溃但如果部署时忽略了对哨兵进程的监控比如没有纳入 systemd 或 Supervisor 管理一旦哨兵因为内存溢出或文件权限意外退出整个高可用架构等于没了一半。这次测试给我一个明确结论哨兵本身也要做守护最稳妥的方式是每个哨兵都用 systemd 托管设置Restartalways。我贴下当时用的 systemd 单元文件供参考[Unit] DescriptionRedis Sentinel Afternetwork.target [Service] Typeforking ExecStart/usr/local/bin/redis-sentinel /etc/redis/sentinel.conf ExecStop/usr/local/bin/redis-cli -p 26379 shutdown Restartalways RestartSec5 [Install] WantedBymulti-user.target配置好后systemctl daemon-reload systemctl enable redis-sentinel systemctl start redis-sentinel5. 故障转移的关键行为与选举逻辑5.1 为什么选它当新主节点很多刚接触哨兵的朋友会问我新主节点是怎么挑出来的是随机吗当然不是。哨兵在选择从节点时会按以下顺序筛选过滤掉断线、主观下线、最近没响应过的从节点过滤掉与主节点断线时间超过down-after-milliseconds的从节点这是为了确保候选从节点中的数据足够新尽量少丢数据剔除复制偏移量过于落后的从节点不同版本处理方式有差异本质上都是为了选出数据最完整的从节点在剩余节点中依据slave-priority排序优先级数字越小越优先如果优先级相同比较复制偏移量replication offset偏移量越大说明数据越完整优先被选如果以上条件都相同再比较 Run ID按字典序选择最小的。这里特别提醒一点复制偏移量是判断“哪个从节点数据最新”的关键指标。如果某个从节点之前长时间断开它的复制偏移量就会大幅度落后其他从节点即使它被提升为新主节点也会丢失更多数据。所以平时要注意监控各从节点的master_link_down_since_seconds一旦发现从节点掉线太久要优先处理。5.2 脑裂问题旧主节点突然复活生产环境中更复杂的场景是主节点并不是真正宕机而是发生了网络分区network partition。这时候可能会出现“脑裂”效应一方面哨兵把某个从节点提升为新主另一方面旧主节点仍在运行且依然接收写请求导致两端数据不一致。Redis 哨兵方案对脑裂的防护机制是min-replicas-to-write和min-replicas-max-lag这两个配置项。它们虽然定义在主节点配置中但作用是保护主节点在失去大部分从节点连接时主动拒绝写入从而避免分区期间写入无法同步的数据。典型设置# 主节点最少要有 1 个从节点在线否则拒绝写 min-replicas-to-write 1 # 从节点的数据延迟不能超过 10 秒否则拒绝写 min-replicas-max-lag 10也就是说如果旧主节点发现自己与从节点之间的复制断裂超过 10 秒并且连不上足够数量的从节点它会自动进入只读状态不再接收业务写入。这样即使发生脑裂旧主上产生的脏数据也极其有限。注意min-replicas-to-write不能设置太高比如从节点只有 2 个时如果设置为 3主节点会因为永远凑不够从节点而持续拒绝写入相当于白配置了。一般建议不超过“从节点总数减一”。5.3 客户端连接哨兵的正确方式很多人以为配置了哨兵模式后客户端仍然直接连 Redis 主节点的地址。其实不对正确姿势是客户端连哨兵的地址并指定 master 名称由哨兵返回当前主节点信息。以 Java 的 Lettuce 客户端为例Spring Boot 中的默认客户端ListRedisNode sentinels Arrays.asList( RedisNode.newRedisNode().withHost(192.168.56.101).withPort(26379).build(), RedisNode.newRedisNode().withHost(192.168.56.102).withPort(26379).build(), RedisNode.newRedisNode().withHost(192.168.56.103).withPort(26379).build() ); RedisURI redisURI RedisURI.Builder .sentinel(sentinels, mymaster) .build(); RedisClient client RedisClient.create(redisURI);这样配置后当主节点切换时客户端可以自动感知到新主节点业务无需重启连接池也会自动刷新。我实测过在故障转移过程中客户端请求会出现几秒的阻塞或异常但随后自动恢复不会一直连不上。如果你还在用 Jedis配置思路类似JedisSentinelPool接收哨兵地址列表和 master 名称。这里有个细节哨兵模式下客户端必须同时配置所有哨兵的连接地址不能只配一个避免单个哨兵不可用时客户端完全失联。5.4 哨兵模式的网络与安全注意事项哨兵节点之间使用 Redis 自定义协议通信默认端口 26379。这个端口建议在防火墙中对可信的哨兵节点 IP 放行即可不要对所有来源开放。同时如果哨兵配置了sentinel auth-pass哨兵之间的通信也会进行认证推荐生产环境开启。另外哨兵配置文件在故障转移后会动态变化。每次切换完成后哨兵会把“当前主节点地址”写回自己的sentinel.conf中这就是我前面说的“配置文件重写机制”。也就是说你如果手动改过sentinel.conf中的主节点 IP在运行一段时间后可能发现又被改回去了——这是哨兵正常运行的表现千万别以为配置被“篡改”了。因为这种动态重写机制运维上要特别注意sentinel.conf要有写权限当前用户或 root否则哨兵无法更新状态甚至可能直接报错退出。6. 常见问题与排查技法实录6.1 哨兵日志中的 sdown 与 odown 到底怎么回事排查哨兵故障第一步永远是看日志。我遇到过不少同事看到日志里刷sdown就以为 Redis 挂了急得不行。实际上sdown只是单个哨兵的主观判断有可能是网络抖动、哨兵自己的连接问题甚至 Redis 节点只是正在执行耗时命令比如KEYS *暂时阻塞了事件循环。只有当odown出现才代表多数哨兵都认为主节点失联才会触发后续动作。如果你看到日志里持续出现sdown和-sdown交替出现即主观下线又恢复但始终没有odown那大概率是网络质量不稳定或哨兵与主节点之间的连接被防火墙掐断。这种情况优先检查网络而不是急着调配置。6.2 为什么哨兵之间互相发现不了最常见的原因是防火墙没有放行 26379 端口其次是sentinel announce-ip没有配置尤其是在多网卡或云主机场景下。哨兵发现彼此用的是运行 ID IP 端口如果广播的 IP 是云平台内网地址而实际通信走的是另一个网段就会互相失联。排查步骤# 检查本机监听状态 ss -lntp | grep 26379 # 检查防火墙 firewall-cmd --list-all如果是系统防火墙问题放行端口firewall-cmd --zonepublic --add-port26379/tcp --permanent firewall-cmd --reload云主机还要检查安全组规则这一步最容易漏。6.3 配置了哨兵后主从复制报错 NOAUTH如果 Redis 主节点设置了requirepass从节点和哨兵都需要知道密码。从节点配置masterauth指定主节点密码哨兵配置sentinel auth-pass指定主节点认证密码缺一不可。我踩过的一个坑是只配了requirepass从节点同步时报NOAUTH Authentication required主从复制一直无法建立。后来把masterauth加上后秒恢复。注意这个错误不会导致进程崩溃Redis 会反复重试但主从就是同步不了监控上非常隐蔽。6.4 故障转移完成后客户端仍然连不上新主节点如果客户端直接配置了旧主节点地址、而不是走哨兵那故障转移后连接必然失败。正确做法是客户端通过哨兵获取主节点地址或者依赖客户端自身的哨兵支持。如果已经使用了哨兵模式但切换后仍然出现大量连接超时可能是客户端连接池没有及时刷新。排查时先看客户端日志确认是否还在连接旧 IP。部分老版本客户端有较长缓存时间可以考虑配置更短的连接刷新周期。6.5 自动故障转移被反复触发业务频繁中断这种情况通常发生在网络抖动频繁或down-after-milliseconds设置过短时。网络抖动让哨兵误以为主节点失联不断地走完整个切换流程。频繁切换对业务影响很大每次切换都会造成连接池重建、数据短暂不可写。解决办法把down-after-milliseconds调大比如 10000 毫秒以上检查主节点是否因执行慢查询阻塞事件循环导致哨兵 ping 超时检查各节点系统时钟是否同步时钟漂移严重时哨兵的判断会失准。6.6 哨兵切换时间到底有多长如何优化从上面实验来看从主节点失联到切换完成总共 7 秒左右。这个时间主要由几部分组成哨兵发现主节点失联的时间取决于down-after-milliseconds实验设置的是 5 秒哨兵之间确认和选举 Leader毫秒级从节点提升和其余从节点重新同步取决于从节点数量和网络。如果你希望切换更快可以把down-after-milliseconds调小到 3 秒。但这是双刃剑网络抖动时更容易误判切换。以我的经验内网业务追求高可用3 秒可以接受跨机房部署宁可多等几秒也别频繁切换。6.7 核心命令速查最后整理一份哨兵运维常用命令方便参考作用命令查看哨兵全局状态redis-cli -p 26379 info sentinel查看主节点信息redis-cli -p 26379 sentinel master mymaster查看从节点列表redis-cli -p 26379 sentinel slaves mymaster查看哨兵列表redis-cli -p 26379 sentinel sentinels mymaster手动触发故障转移redis-cli -p 26379 sentinel failover mymaster动态修改 quorumredis-cli -p 26379 sentinel set mymaster quorum 1查看主从复制状态redis-cli -p 6379 info replication其中sentinel failover命令尤其值得推荐它可以手动强制执行一次故障转移不需要真的把主节点杀掉非常适合日常演练和验证配置正确性。我每次调整完哨兵参数都会主动跑一次手动 failover确认整个链路通畅后才放心。7. 我对哨兵模式的使用体会哨兵模式算不上复杂但它架构设计精妙把分布式系统里最棘手的“自动检测、协商决策、状态收敛”三件事浓缩到了几个配置项里。我维护过的几个项目从单机到主从再到哨兵确实踩了不少坑但也因此积累了一套稳妥的部署套路。几点个人体会分享给读者第一不要追求“一步到位的高可用”。如果你没接触过主从复制建议先把主从架构搭明白、把数据同步的原理搞清楚再上哨兵。否则一旦故障转移出现数据不一致你很难判断是复制问题还是哨兵问题。第二哨兵确实不等于零丢失。它保证的是“Redis 服务尽量可用”而不是“数据一笔不丢”。如果你的业务对写丢失极其敏感宁可引入数据异步落盘、消息队列补偿等手段也不能单纯依赖哨兵模式。第三定期做故障演练比看配置文档重要得多。每个季度手动 kill 一次主节点观察哨兵的日志、切换耗时、客户端自动恢复情况顺便验证监控告警链路是否正常。真到了线上事故爆发那一刻你的信心完全来源于平时演练过多少次。第四如果长期用 Redis 做核心存储且规模不断变大展望后面方向时可以考虑集群模式。哨兵模式适合单主多从的架构如果数据量大到单主内存扛不住、需要横向扩展到多个分片那就要研究 Redis Cluster 了。两者解决的问题不同并不是替代关系架构选型时要先想清楚。最后再分享一个小技巧排查哨兵问题时不要只看一台机器上的sentinel.log因为哨兵之间是独立决策的某台机器的日志可能只反映了它的视角。三台机器的日志要配合着看特别是判断客观下线、选举 Leader 时交叉对比各个哨兵的时间线和日志关键字还原出的故障过程才会完整。哨兵模式这套东西用好了是真的稳用不好也是真的容易在关键时刻掉链子。希望这篇内容能帮你少走一些弯路。