1. 从“主从挂了怎么办”说起:哨兵到底在解决什么问题
我经常在技术交流群里看到一种很典型的问题:把 Redis 搭成了主从架构,一台主节点带着两台从节点,觉得“这总该稳了吧”。结果某天主节点所在服务器磁盘写满,或者内存被某个大 Key 打爆导致进程 OOM,主节点一挂,从节点虽然数据还在,但应用根本不会自动把写请求切到从库上去。于是线上告警、业务报错、一堆人围着数据库层排查——这时候才意识到,光是主从复制根本解决不了“高可用”。
这就是 Redis 哨兵(Sentinel)存在的理由。它不是一个存储组件,也不是又一个 Redis 实例,而是一套独立运行的监控与故障转移系统。它盯着你的主节点和从节点,一旦发现主节点“不行了”,就自动在从节点里挑一个扶正成新的主节点,同时通知客户端去连新的主节点。整个过程不需要人半夜爬起来手动改配置,也不需要业务方写什么复杂脚本。
哨兵还顺带解决了另两个容易被忽视的问题。第一是配置提供:当主节点发生切换后,客户端怎么知道新主是谁?总不能让每台应用服务器都手工改一遍连接地址,那还不如不用哨兵。哨兵本身可以当作一个“查询服务”,客户端通过它拿到当前的主节点地址,切换后自动得到新地址。第二是通知:主节点故障后,哨兵能通过回调脚本等方式通知运维方,把“故障已发生”这件事广播出去,方便值班人员介入排查。
所以,一句话概括:Redis 单机解决的是“数据能存”,主从复制解决的是“数据有备份、读能扩展”,哨兵解决的是“主节点挂了之后,系统还能自动继续干活”。这三者不是互相替代的关系,而是层层递进的关系。我做过不少 Redis 高可用方案,我的建议很直接:凡是线上用了主从架构但没接哨兵的,本质上都不算真正的生产高可用——只是把单点从一台机器迁移到了“主节点那一台机器”上而已。
从拓扑上看,哨兵本身也是一个集群,最少部署三个节点,彼此之间通过发布订阅和 Gossip 协议交换对主节点的看法。为什么要三台起步?因为故障转移必须依赖“多数派投票”,如果只有一两个哨兵,万一哨兵自身所在的机器网络抖动,或者哨兵进程挂了一个,剩下的哨兵就凑不齐法定票数,本来就该做的故障转移反而做不了。所以最少三台,并且建议和 Redis 实例分机部署,别图省事全都塞同一台物理机上——否则宿主机一宕,Redis 和哨兵一起失踪,高可用直接变成“高不可用”。这个话题后面我会详细展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 哨兵的两个“绝招”:监控判定和故障转移的完整链路
很多人对哨兵的理解停留在“它能自动切换主节点”,但具体怎么判定主节点挂了、怎么防止误判、切换时数据一致性怎么保证,这些细节才是真正影响线上可靠性的地方。我拆开讲。
2.1 主观下线(sdown)是怎么触发的
每个哨兵会以每秒一次的频率,向它监控的所有主节点、从节点以及其余哨兵发送 PING 命令,并等待回复。这个 PING 不是普通的连接探活,而是 Redis 协议层面的一问一答——只要对方进程活着且事件循环正常,就会很快返回 PONG。
如果某个哨兵在配置的 down-after-milliseconds 时间内(默认 30 秒)没有收到有效回复,它就在本地把该节点标记为“主观下线”(sdown)。注意“主观”这两个字:这个结论只代表这一个哨兵的判断,可能是真的宕机,也可能只是网络抖动、瞬时阻塞、甚至那个哨兵自己跟 Redis 之间的链路出了问题。单靠一个哨兵的主观判断就切换主节点,风险很大,所以后面还有第二道关卡。
2.2 客观下线(odown)与法定票数
一个哨兵把主节点标记为 sdown 之后,会通过 sentinel is-master-down-by-addr 命令,把这个判断广播给其他哨兵。其他哨兵收到后会回复自己对该主节点的检查结果:同意还是不同意。
当在指定时间内,同意“该主节点已挂”的哨兵数量达到配置文件里的 quorum 值(通常设为 2),这个主节点就被标记为“客观下线”(odown)。客观下线是触发故障转移的前提。quorum 的取值不是越大越好,它需要结合哨兵总节点数来定。比如三哨兵集群,quorum 设 2,那么最多允许一个哨兵失联或产生误判;如果 quorum 设 1,那几乎只要任意一个哨兵说挂就切换,误判概率大增,不适合生产环境。我自己的经验是:三哨兵配 quorum=2,五哨兵配 quorum=3,既能容忍部分哨兵故障,又能防止单点误判导致全网切换。
这里有个细节很多人会踩:客观下线只针对主节点生效,从节点挂了不会触发故障转移流程。从节点挂掉后,哨兵只是把它标记为下线,等它恢复后重新加入复制关系。原因也很简单——从节点不承担写流量,挂了不影响主流程,顶多让读能力降级,没必要为一个从库去折腾新一轮选举。
2.3 故障转移:从“选新主”到“改配置”的四步走
一旦主节点被确认为客观下线,哨兵集群会进入故障转移流程。整个过程大致可以拆成四步:
第一步,选举主导者。多个哨兵都发现主节点客观下线后,谁来做故障转移的执行人?通过类似 Raft 的投票机制,哨兵之间相互投票,得票过半的哨兵成为领导者,负责接下来的全部切换动作。这个设计避免多个哨兵同时操作同一批从节点导致配置混乱。
第二步,筛选候选从节点。领导者会过滤掉两个类别的从节点:一种是断线时间超过一定阈值的——说明它跟主节点断开太久,数据落后太多,不适合直接接棒;另一种是处于下线状态、或者和主节点失联时间过长的。筛选后,剩下的从节点按优先级 slave-priority 排序,优先级相同则比较复制偏移量,偏移量越大说明从节点收到的数据越接近旧主,越适合当选。
第三步,执行切换。领导者向选中的从节点发送 REPLICAOF NO ONE,让它解除从属关系,变成新的主节点,并开始对外提供写服务。随后,领导者会让其余从节点执行 REPLICAOF 新主地址 新主端口,把它们挂到新主节点底下重新开始复制。这一步是原地修改内存状态,不是重启进程,几十毫秒内就能完成。
第四步,配置重写与通知。原来的主节点地址会被记录到哨兵的配置里,标记为“曾经的故障主节点”。等它恢复上线后,哨兵会发现它已经不再是主节点,然后自动把它降级为新主节点的从节点。与此同时,哨兵通过频道发布新主节点信息,订阅了该频道的客户端就能收到变更事件,重新建立连接。
我讲得比较平铺直叙,但实际操作里,第二步和第三步之间藏着不少坑,比如从节点选举时的数据一致性校验、切换过程中的短暂拒绝服务窗口、以及客户端感知新主地址的延迟。这些后面我结合故障演练单独说。
3. 部署一套生产可用的哨兵:配置文件、参数调优与拓扑设计
哨兵的模式并不复杂,但“能跑起来”和“生产可用”之间差着一大截。这一节我按实际部署的先后顺序,把配置、参数、拓扑和踩坑经验一次说清。
3.1 基础配置:sentinel.conf 里每行都是什么
假设你已经有一主两从的 Redis 集群,主节点地址是 10.0.0.11:6379,从节点分别是 10.0.0.12 和 10.0.0.13。那么三台哨兵节点上,sentinel.conf 的核心内容大致如下:
code复制port 26379
dir /var/lib/redis-sentinel
sentinel monitor mymaster 10.0.0.11 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 15000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster yourpassword
protected-mode no
daemonize no
逐行解释一下关键参数。
port 26379 是哨兵自身的监听端口,客户端和哨兵之间、哨兵和哨兵之间都走这个端口,别跟 Redis 的 6379 混了。
sentinel monitor mymaster 10.0.0.11 6379 2 这行是核心。它定义了一个名为 mymaster(名字随便起,但要统一)的监控对象,后面跟的是初始主节点地址和端口,最后的 2 就是前面说的 quorum。这个配置含义是:必须至少 2 个哨兵同意主节点挂了,才会触发切换。
sentinel down-after-milliseconds mymaster 5000 是主观下线的判定窗口。默认 30 秒太长,我生产环境一般调成 5000 毫秒,也就是连续 5 秒没有 PONG 响应就标记主观下线。不要为了“更灵敏”把它调到 1000 毫秒,那样主节点稍微做一次大 Key 清理导致事件循环卡顿几百毫秒,就会触发一连串不必要的切换。判断时间需要留出“抖动容忍”。
sentinel failover-timeout mymaster 15000 是故障转移超时时间。它控制一次切换操作从选举到执行的整个流程必须在 15 秒内完成,超时则视为失败,重新走选举。这个时间要和上面两个参数配合,避免“明明在做切换、客户端却在等待很长的连接超时”。
sentinel parallel-syncs mymaster 1 最有意思。它规定切换完成后,同时向多少个新主节点发起同步复制请求的从节点数。建议设成 1,也就是让从节点一个一个地重新复制。如果设成 2 或更大,所有从节点同时向新主发起全量同步,新主节点的带宽和 CPU 会瞬间被打满,极端情况下新主也扛不住,二次故障。生产环境我从来没设过大于 1 的值。
如果 Redis 开启了 requirepass,记得加 sentinel auth-pass;如果主从之间用了不同的密码,也要分别配置。很多人在这一步漏掉,导致哨兵能连接、但 PING 阶段就因认证失败而被判下线,雪上加霜。
3.2 拓扑设计:三哨兵都放哪台机器
我看到过很多种部署方案,有的把三个哨兵和三个 Redis 实例全部跑在同一批机器上,有的则把哨兵单独拆三台小机器。哪种更合理?我的结论是:哨兵必须和 Redis 实例“同故障域隔离”。
什么叫同故障域隔离?简单说,不要让哨兵挂在和 Redis 完全相同的物理宿主机或同一可用区内。否则,宿主机宕机会同时带走 Redis 和哨兵,哨兵数量直接跌破多数派,故障转移永远无法触发——高可用架构在最需要的时刻反而失效。
比较推荐的部署方式有两种:
| 部署方案 | 拓扑描述 | 适用场景 |
|---|---|---|
| 方案 A:哨兵独立三台 | 3 台哨兵单独部署,Redis 一主两从分布在另一批机器 | 线上核心链路,硬件资源充裕 |
| 方案 B:哨兵随从节点部署 | 哨兵放在从节点所在机器上,主节点所在机器不放哨兵 | 中小规模项目,机器数量有限 |
方案 B 是我在资源紧张时用得最多的:主节点那台机器上不部署任何哨兵,哨兵跟着从节点走。这样即使主节点宿主机整个宕机,三台哨兵仍然全部存活,可以顺利执行切换。等旧主恢复后,哨兵自然会把它变成新主的从节点。这个方案的弊端是如果两台从节点所在机器同机房故障,仍然会失去两台哨兵,因此对机房的容灾要求更高。
不管哪种方案,哨兵之间必须网络互通、时间同步。时间漂移超过阈值会导致节点间对“某个节点多久没响应”的判定产生偏差,进而影响投票一致性。部署完用 ntpdate 或其他时间同步工具对齐一下,别忽略这个细节。
3.3 客户端怎么找到新主:从“手动改地址”到“动态发现”
配置好哨兵之后,应用的连接方式也要跟着改。很多项目之前是直接把主节点 IP 写死在配置文件里,接了哨兵之后还是这么干,那等于没接。正确的做法是,客户端通过哨兵获取当前主节点地址。
以常见的 Java 客户端为例,Jedis 里用 JedisSentinelPool,构造时传入哨兵地址列表和 master 名字,客户端会连接任意一个哨兵,执行 sentinel get-master-addr-by-name 拉取当前主节点。当主节点切换后,哨兵会通过发布订阅推送给客户端,客户端自动重连新主。
其他语言的客户端理念相同:连接哨兵,而不是直接连接 Redis。这里有个很实际的建议:哨兵地址列表写全部三个哨兵的地址,而不是只写一个。因为如果一个哨兵正好在故障转移期间重启,客户端连不上它,就会尝试下一个,有冗余才不容易断。选型时也注意,部分老旧的客户端库对哨兵模式的故障转移重连支持不完善,测试环境要专门做一次“杀掉主节点看客户端反应”的演练,别等线上出事才暴露。
3.4 配置重写的隐藏机制
哨兵还有个容易被忽略的行为:它会在运行过程中自动修改自己的配置文件。比如主节点切换后,哨兵会把 sentinel monitor 那一行的主节点地址从旧 IP 改写为新 IP,同时更新已知从节点的列表。
这个设计的初衷是让哨兵在重启后依然能记住当前拓扑状态。但也带来一个运维隐患:如果人工改动 sentinel.conf 后没触发哨兵的重写机制,或者多个哨兵配置不一致,就会导致诡异的问题。比如我遇到过:运维同事手动把配置文件里的主节点 IP 改回旧地址,结果哨兵一运行又自动改回新地址,两边“打架”。所以,在哨兵模式下,不要手动修改已经运行中的哨兵配置文件,要用命令动态调参,比如 SENTINEL SET,让它自己把配置落盘。动态修改走命令通道,既能生效又能保证配置收敛一致。
4. 故障转移实战:从模拟宕机到恢复的完整排查过程
理论说得再多,不如动手做一次故障演练。我拿一套模拟环境来演示完整的流程,这套流程我在很多项目里都跑过,照着做基本能暴露绝大多数配置问题。
4.1 演练环境与初始状态
模拟环境使用三台节点:
| 角色 | 地址 | 说明 |
|---|---|---|
| 主节点 | 192.168.1.11:6379 | 初始 master |
| 从节点 A | 192.168.1.12:6379 | slave |
| 从节点 B | 192.168.1.13:6379 | slave |
| 哨兵 S1 | 192.168.1.21:26379 | 监控 mymaster |
| 哨兵 S2 | 192.168.1.22:26379 | 监控 mymaster |
| 哨兵 S3 | 192.168.1.23:26379 | 监控 mymaster |
quorum 设为 2,down-after-milliseconds 设为 5000。演练前,先往里写一条测试数据,比如 SET biz:order:20250101 OK,确保故障转移后这条数据还在从节点上(如果主节点是被强杀而非优雅退出,最后写入的数据是否复制到从节点要观察偏移量)。
4.2 第一步:制造主节点“假死”
最直接的模拟方式是强制杀掉主节点 Redis 进程:
bash复制redis-cli -h 192.168.1.11 -p 6379 shutdown nosave
注意我用的是 shutdown nosave,模拟的是进程异常终止且不做 RDB 持久化,这比直接 kill -9 干净一点,但效果接近。如果用 kill -9,主节点不会有任何善后动作,对哨兵来说二者差别不大。
杀掉后,立刻观察哨兵日志,通常主节点宕机几秒后,日志会出现类似内容:
code复制+monitor master mymaster 192.168.1.11 6379
+sdown master mymaster 192.168.1.11 6379
+odown master mymaster 192.168.1.11 6379 #quorum 2/2
+try-failover master mymaster 192.168.1.11 6379
+switch-master mymaster 192.168.1.11 6379 192.168.1.12 6379
一步步解释:先是 +sdown,说明某个哨兵率先判定主观下线;然后出现 +odown #quorum 2/2,说明两个哨兵达成一致,客观下线成立;随后是 +try-failover 和 +switch-master,新主节点被选定为 192.168.1.12。
如果你看到日志卡在 +sdown 之后迟迟不出现 +odown,说明 quorum 没凑齐。这时去查另外两个哨兵的日志,多半是网络隔离、认证失败、或者 down-after-milliseconds 差距过大导致判定时间不一致。排查顺序:先 redis-cli -p 26379 sentinel master mymaster 看每个哨兵维护的状态,再对比各哨兵看到的同一主节点的“上次响应时间”,即可定位是哪个哨兵没有同步判断。
4.3 第二步:验证从节点角色变化和新主数据
切换完成后,先确认 192.168.1.12 已经变为主节点:
bash复制redis-cli -h 192.168.1.12 -p 6379 info replication
输出结果里 role:master 就说明成功。然后立刻查看从节点 B 的复制关系:
bash复制redis-cli -h 192.168.1.13 -p 6379 info replication
正常情况下它的 master_host 已经变成了 192.168.1.12。这里我强调一下:从节点日志里会有几十毫秒到百毫秒级别的等待,因为哨兵要逐台执行同步指令,parallel-syncs=1 时尤其明显,不要慌,那是正常现象。
数据层面,去新主节点上查询演练前写入的 biz:order:20250101。如果查到了,说明旧主的数据已经完整复制到了新主;如果没查到,就要对比旧主的复制偏移量和从节点的偏移量,确认故障发生时哪些数据尚未同步——这关系到业务可接受的数据丢失窗口。这个窗口不是哨兵造成的,而是异步复制本身固有的:主节点刷盘后返回写成功,但从节点还没收到这条写命令时主节点挂了,这条数据就丢了。哨兵只能保证“尽量选偏移量最大的从节点来当新主”,不能保证零丢失。对强一致性有要求的业务,得在客户端层做双写或者其他兜底方案,不能把账全算在哨兵头上。
4.4 第三步:让旧主“复活”,看它如何降级
把原来那台 192.168.1.11 的 Redis 重新启动。启动后它的角色不会自动变回主节点,哨兵会检测到它上线,然后自动执行 REPLICAOF 192.168.1.12 6379,让它作为从节点重新接入集群。
这个环节常出的一个坑是:旧主启动时因为配置里没有 replicaof 指令,它会以“无主模式”启动。如果旧主启动后发现自己是“主”状态,但哨兵还没来得及把它降级,此时它仍然可以接受写入——这段窗口里如果应用端还在往旧主发数据,就形成了“双主写”脑裂。所以要避免这个问题,除了依赖哨兵的自动降级,还应该在业务层面设置合理的连接超时和重连逻辑,让客户端尽快切到新主。正常情况下,哨兵在几秒到十几秒内就会把旧主降级,但窗口确实存在,预案要想在前头。
4.5 次生故障演练:哨兵自己也挂了怎么办
生产上还有种情况:主节点没事,但某个哨兵进程挂了。这时哨兵集群数量变少,只要不是挂到跌破半数,不影响监控和切换能力。比如三哨兵挂了一个,quorum=2 仍然可以凑齐,切换照常执行。但如果三哨兵挂了两个,整个集群就做不了客观下线判定——即使主节点真挂了,也因为凑不齐 2 个同意票而无法切换。
这就是我前面强调“哨兵至少要三个、并且最好隔离部署”的原因。故障演练时一定要把“哨兵挂一个”和“哨兵挂两个”这两种情况都做一遍,确认应对一致。五哨兵配 quorum=3 甚至理论上可以容忍两个哨兵同时故障,但生产环境一般不会单独为 Redis 高可用铺五台哨兵节点,成本考量下三哨兵是主流。
5. 哨兵模式下那些暗坑:脑裂、配置飘移与客户端感知延迟
哨兵不是银弹,部署了也不代表从此高枕无忧。我在线上见过的问题,说几个最常见的。
5.1 脑裂:旧主其实没宕机,但被切了
前面模拟的是主节点真死,但生产中还有一种更棘手的情况:主节点和哨兵之间的网络被切断了,主节点本身还在正常运行,还能接受写请求。由于哨兵收不到 PONG,经过 down-after-milliseconds 后在 quorum 票数支持下完成故障转移,选出新主。这时就出现了“两个主”同时存在的脑裂场景。
脑裂的核心危害是数据分叉:旧主持续接收写入,新主也接收写入,两边数据各自独立,旧主恢复网络后降级为从节点,做全量同步时会把自身持有的数据丢弃——旧主在脑裂期间写入的数据全部丢失。这对某些业务是灾难级的。
Redis 官方其实没有在哨兵层直接消除脑裂的机制,但可以缓解。一个有效手段是设置主节点的 min-replicas-to-write 和 min-replicas-max-lag。前者表示当从节点数小于某个值时就拒绝写请求,后者表示允许从节点最大落后多少秒。这两个参数组合后的效果是:当主节点失联导致从节点都连不上它(或者复制链路过期)时,主节点会主动拒绝写入,避免脑裂期间产生“孤儿数据”。比如配置:
code复制min-replicas-to-write 1
min-replicas-max-lag 10
意思是至少要有 1 个从节点且复制延迟在 10 秒以内,主节点才接受写入。当主节点被网络隔离,从节点超过 10 秒没同步数据,主节点立刻拒绝写入,业务相关方会收到写入失败,但至少不会产生脑裂后不可挽回的分叉数据。这是用“牺牲短暂可用性”换取“数据一致性”的典型取舍。
5.2 配置飘移:哨兵改了我的配置,我改不回来了
哨兵自动重写配置文件这个设计,前面说了是保证重启后可恢复拓扑状态。但它在运维层面也带来一个麻烦:如果你想人工调整监控对象,比如把 sentinel monitor 的主节点从 A 切到 B,直接编辑配置文件是没有用的——运行中的哨兵会以自己内存里的状态为准,等你下次重启时又会重写回 B。正确操作是:
bash复制redis-cli -p 26379 sentinel failover mymaster
执行后哨兵会立即发起一次故障转移,把主节点切换到当前健康的从节点,并把配置自动更新。如果只是想临时修改某个参数,用 SENTINEL SET mymaster down-after-milliseconds 10000 这样的命令动态调整。记住:在哨兵环境里,改配置一律走命令,不要手动改文件。我在项目里就吃过手动改文件的亏,改完重启哨兵,结果配置又变回原样,整整排查了一下午。
5.3 客户端感知延迟:切换完成了,但请求还往旧主发
故障转移完成后,哨兵侧一切恢复正常,但客户端侧未必同步。很多客户端库对哨兵主节点变更的感知方式是通过订阅哨兵的 +switch-master 频道,收到消息后重建连接池。这个过程通常很快,但存在一个时间差:在故障转移刚完成、客户端还没收到通知的窗口内,应用如果继续往旧主写,而旧主此刻已经宕机或者降级,写请求就会失败。
应对思路有两个层面。第一是在业务侧设置合理的重试机制,写失败后捕获异常,等几百毫秒再重试一次,此时客户端通常已经完成新主发现,第二次写会成功。第二是客户端池化配置里设置较短的连接废弃时间,避免“连接到已死亡旧主”的长连接一直占着资源。还有一点很容易忽略:连接池中可能存在多个到旧主的连接,切换通知只能触发新建连接,已建立的连接需要被检测到失效才会替换,因此需要配合 Redis 客户端的 testOnBorrow 或类似心跳机制,确保读取时发现连接不可用就立即重建。这个优化对高并发写入场景特别重要,否则每次写请求都要先失败一次再重建连接,用户体验会很差。
5.4 哨兵模式与集群模式的边界
经常有人问:有了哨兵高可用,还需要 Redis Cluster 吗?这两者解决的不是同一个问题。哨兵针对的是单主架构的高可用,主节点只能有一个,从节点可以用来读,但不承担分片。数据量到了一定规模后,单主节点内存可能也装不下,写性能也会触及单线程瓶颈,这时候需要 Redis Cluster 做水平拆分,把数据分散到多个分片,每个分片各自可以再搭主从。Cluster 自带槽位管理和故障转移能力,不需要再额外套一层哨兵。
我遇到最常见的错误认知是“哨兵模式支持自动分片”,或者“Cluster 模式下不需要哨兵”。前者是概念混淆,后者倒是基本正确的——Cluster 自己会处理节点故障,但它在节点发现、故障判定机制上和哨兵是两套逻辑,不能把哨兵的配置文件直接搬过去用。选型时,先看数据量和写入吞吐量:单主能扛住、请求量不大,优先哨兵;数据量大、需要在线水平扩展,上 Cluster。架构上没必要为了一套高可用方案同时叠加哨兵和 Cluster,那只会让运维复杂度翻倍。
6. 实战总结:我的哨兵部署经验与最后几条建议
做 Redis 哨兵部署这么多次,我最后的感受是:哨兵的难点从来不在配置项本身,而在于把网络故障、客户端感知、数据一致性这些环节想周全。线上稳定运行不是靠某个“聪明”的参数,而是靠一套完整的预案和演练。
我个人的部署习惯是:主从和哨兵的机器全部使用内网独立 IP,不开公网访问;哨兵端口只在运维网段内开放;Redi s 本身开启 requirepass 和 rename-command 限制危险命令;每个哨兵进程用 systemd 托管,配置自动重启,防止哨兵进程因为内存泄漏或者其他原因悄然退出。
配置参数上,我通常的基线参考是:
| 参数 | 选值 | 原因 |
|---|---|---|
| down-after-milliseconds | 5000 | 容忍抖动,又足够灵敏 |
| failover-timeout | 15000 | 与上线判定窗口匹配,避免切换拖沓 |
| parallel-syncs | 1 | 串行重同步,保护新主 |
| quorum | 2(三哨兵)/3(五哨兵) | 兼顾可用性和容错性 |
另外,每个季度做一次故障演练,演练不是走过场,而是要把“进程宕机、服务器重启、网络隔离”三种故障都模拟一遍,记录从故障发生到切换完成的耗时,形成基线数据。只有演练时验证过的方案,发生真实故障时才值得依赖。
最后说一个小技巧:哨兵日志是排障时最直接的依据,建议把日志级别设为 notice 并用 systemd 统一采集,发生切换时快速在日志里搜索 +sdown、+odown、+switch-master 这几个关键字,能在很短时间内串起完整事件线。我在真实故障排查中,基本全靠这几条日志定位问题——看到 +odown 但没看到 +switch-master,就知道故障转移卡在选举或筛选环节;看到 +switch-master 但客户端还在报错,就知道问题出在客户端感知或连接池上。学会读哨兵的日志,等于拥有了整个高可用链路的“黑匣子”。
