news 2026/10/21 6:51:59

Redis哨兵模式全解析:高可用架构原理与故障转移实操

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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规定的时间内没有响应,哨兵就认为这个节点主观下线(sdown,subjective down)。但注意,一个哨兵说了不算,因为可能是网络抖动或哨兵自己的问题,所以需要多个哨兵互相确认。当多个哨兵都认为主节点挂了,并且数量达到quorum设定的阈值,这时主节点才会被标记为客观下线(odown,objective down),然后触发故障转移流程。

这个设计逻辑很像我们工作中的“举手表决”——不能只听一个人说“不行了”,要让多个独立的观察者都确认才算数。这样做能有效避免单点哨兵误判导致频繁切换、主备脑裂等问题。

故障转移的过程可以拆成这几步:

  1. 领先的哨兵节点(Leader)从所有健康的从节点里挑一个,通过SLAVEOF NO ONE命令把它提升为主节点。
  2. 其他从节点收到新配置后,自动去同步新主节点的数据。
  3. 哨兵们更新内存中的主节点地址,并向客户端发布新的连接信息。
  4. 如果原来的主节点恢复了,它会发现自己的角色变了,自动降级为新主节点的从节点,老老实实去同步数据。

哨兵架构还存在一个“配置提供者”的功能,经常被忽略但非常实用:客户端连接 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.9,Redis 版本 6.0.16:

主机名IP节点角色端口
redis-master192.168.56.101Redis 主节点6379
redis-slave-1192.168.56.102Redis 从节点 16379
redis-slave-2192.168.56.103Redis 从节点 26379
sentinel-1192.168.56.101哨兵 126379
sentinel-2192.168.56.102哨兵 226379
sentinel-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 install

make 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 会报错,提示不兼容。需要先安装高版本 GCC:

yum 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

两台从节点配置完成后,依次启动三个节点的 Redis:

redis-server /etc/redis/redis.conf

在主节点上查看复制关系:

redis-cli -h 192.168.56.101 -p 6379 info replication

输出类似:

# Replication role:master connected_slaves:2 slave0:ip=192.168.56.102,port=6379,state=online,offset=123456,lag=0 slave1:ip=192.168.56.103,port=6379,state=online,offset=123456,lag=0

看到两个state=online,说明主从复制关系已经建立。这时候可以自己写几条测试数据,在从节点上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:name=mymaster,status=ok,address=192.168.56.101:6379,slaves=2,sentinels=3

重点关注status=ok、slaves=2、sentinels=3。如果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 掉一个后,再用命令查看剩余两个哨兵的状态。两个哨兵之间依然维持正常通信,因为另外两个哨兵仍然存活并组成多数。这时如果主节点故障,剩下的两个哨兵可以凑够 quorum=2,仍然能正常执行故障转移。不过要注意,如果 quorum 也设成 2,而恰好有两台哨兵在同一时间内故障,那就无法触发转移了。这也是为什么生产环境建议“哨兵数量为奇数,且 quorum 等于 (N+1)/2 向上取整”的原因。

哨兵进程本身一般不会崩溃,但如果部署时忽略了对哨兵进程的监控,比如没有纳入 systemd 或 Supervisor 管理,一旦哨兵因为内存溢出或文件权限意外退出,整个高可用架构等于没了一半。这次测试给我一个明确结论:哨兵本身也要做守护,最稳妥的方式是每个哨兵都用 systemd 托管,设置Restart=always。

我贴下当时用的 systemd 单元文件,供参考:

[Unit] Description=Redis Sentinel After=network.target [Service] Type=forking ExecStart=/usr/local/bin/redis-sentinel /etc/redis/sentinel.conf ExecStop=/usr/local/bin/redis-cli -p 26379 shutdown Restart=always RestartSec=5 [Install] WantedBy=multi-user.target

配置好后:

systemctl daemon-reload systemctl enable redis-sentinel systemctl start redis-sentinel

5. 故障转移的关键行为与选举逻辑

5.1 为什么选它当新主节点

很多刚接触哨兵的朋友会问我:新主节点是怎么挑出来的?是随机吗?

当然不是。哨兵在选择从节点时会按以下顺序筛选:

  1. 过滤掉断线、主观下线、最近没响应过的从节点;
  2. 过滤掉与主节点断线时间超过down-after-milliseconds的从节点,这是为了确保候选从节点中的数据足够新,尽量少丢数据;
  3. 剔除复制偏移量过于落后的从节点(不同版本处理方式有差异,本质上都是为了选出数据最完整的从节点);
  4. 在剩余节点中依据slave-priority排序,优先级数字越小越优先;
  5. 如果优先级相同,比较复制偏移量(replication offset),偏移量越大说明数据越完整,优先被选;
  6. 如果以上条件都相同,再比较 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 中的默认客户端):

List<RedisNode> 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 --zone=public --add-port=26379/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 时,交叉对比各个哨兵的时间线和日志关键字,还原出的故障过程才会完整。

哨兵模式这套东西,用好了是真的稳,用不好也是真的容易在关键时刻掉链子。希望这篇内容能帮你少走一些弯路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 6:51:59

STM32盆栽自动管理系统:从湿度监测到微信小程序远程控制详解

简介&#xff1a;基于STM32的盆栽种植自动管理系统设计PDF&#xff0c;面向物联网、嵌入式及微信小程序开发者&#xff0c;针对传统盆栽养护依赖人工经验、数据缺失的问题&#xff0c;提供一套完整的室内绿植智能养护方案。文档从需求分析到软硬件实现均有覆盖&#xff0c;核心…

作者头像 李华
网站建设 2026/10/21 6:51:19

二手交易商品采集与后台同步源码解析:从爬虫到管理后台

简介&#xff1a;抱歉&#xff0c;该资源被明确标注为“转转闲鱼钓鱼源码”&#xff0c;涉嫌仿冒知名二手平台并利用个人二维码收款&#xff0c;可能用于欺诈活动。我不能为此类违法违规资源撰写简介或提供任何形式的推广描述。 1. 资源是什么&#xff1a;一套二手交易场景下的…

作者头像 李华
网站建设 2026/10/21 6:50:50

感应电机无速度传感器FOC控制Simulink仿真与MRAS转速辨识实践

开篇先说一下这个项目的来路。感应电机无速度传感器FOC控制&#xff0c;本质上就是把矢量控制里的“速度传感器”这一环拿掉&#xff0c;用算法把转速信息“估”出来&#xff0c;再配合磁场定向控制实现高性能调速。这个方向在工业传动、电动车辆、家电变频里都用得非常广&…

作者头像 李华
网站建设 2026/10/21 6:50:20

ArcGIS水文分析+HEC-RAS水动力模拟:从DEM到洪水风险图完整链路

搞水文风险分析这么多年&#xff0c;我最大的感触是&#xff1a;单独用GIS做水文分析&#xff0c;容易停留在“纸上谈兵”的程度&#xff1b;单独用HEC-RAS做水力学模拟&#xff0c;又容易卡在“没有靠谱边界条件”的尴尬上。把ArcGIS的水文分析模块和HEC-RAS的水动力学模拟串成…

作者头像 李华
网站建设 2026/10/21 6:50:17

AI眼镜银发市场爆发:视觉增强、语音交互与安全守护成核心

1. 全球出货量暴涨3倍&#xff0c;AI眼镜凭什么撬动“银发”市场1.1 3倍出货量背后&#xff1a;市场阶段已经切换最近行业群里反复出现一个数据&#xff1a;AI眼镜的全球出货量&#xff0c;这个周期里涨了3倍。我头一次看到的时候&#xff0c;第一反应是统计口径是不是变了&…

作者头像 李华