连载中 14/20

哨兵:主从架构的自动值班员

2026-06-01 · 2286 阅读 · 0 评论 · 0 赞

半夜三点,谁去切主

主从复制解决了读扩展与数据冗余,但留了个没人接的活:主库挂了,故障转移靠谁。人工切换意味着半夜告警、手忙脚乱、停服窗口;Redis Sentinel(哨兵)把这个活自动化——它本身不存数据,是一组独立运行的监控进程,干的就一件事:盯着主从,主库失联时自动把合适的从库提升为新主库,再把客户端指过去

下线判定:一票不算,多数投票

哨兵判定主库故障是两段式的,处处透着「别误判」的谨慎。主观下线(sdown):单个哨兵在 down-after-milliseconds 内没收到主库的合理回复,它自己记一笔「我觉得主库挂了」——可能只是这个哨兵自己网络抽风。客观下线(odown):这个哨兵去问其他哨兵「你们觉得呢」,达到 quorum 配置的票数,主库被正式定性为客观下线——网络抖动、哨兵单点故障都被这套仲裁挡在误判之外。

定性之后还有一场选举:多个哨兵协商出一个领队哨兵(leader)来执行切换,选举规则用的就是熟悉的 Raft 多数派思想——必须拿到过半哨兵的同意。所以哨兵要至少部署三个、且奇数:两个哨兵挂一个就凑不出多数派,整套机制瘫在半空。领队选出后执行 failover:从从库里挑一个数据最新的(优先看 offset),提升为新主库,其余从库改挂到新主,旧主恢复后降级为从库。

客户端怎么找到主库

故障转移之后主库地址变了,客户端不能写死 IP——接入哨兵架构时,客户端配置的是哨兵的地址列表,用的时候先问哨兵「主库是谁」,拿到地址再连。主库切换后,哨兵会在订阅频道里发布新主库地址,客户端收到通知刷新本地缓存。这一步让「切换」对业务代码完全透明:

JedisSentinelPool pool = new JedisSentinelPool(
    "mymaster",                       // 主库逻辑名
    Set.of("10.0.0.1:26379",          // 哨兵列表,不是redis地址
           "10.0.0.2:26379",
           "10.0.0.3:26379"),
    poolConfig, "pass");
// 读写主库地址由哨兵实时告知,切换自动跟随

脑裂:旧主还魂的那几秒

哨兵架构有个著名的暗坑叫脑裂:主库与从库之间网络分区,哨兵们判主库客观下线、把某个从库提升为新主——但旧主库还活着,客户端(尤其是没及时收到通知的)还在往旧主写数据。分区恢复后旧主降级为从库、全量同步新主的数据,分区期间写进旧主的那几秒数据,全部蒸发。缓解手段是 min-replicas-to-write 1:主库至少有一个从库在线才接受写入——被孤立的旧主写不进数据,蒸发窗口被大幅压缩。防不到零,但够用。

哨兵解决了高可用,但主从架构的内存天花板没变:一台机器装不下的数据量,加再多从库也没用。哨兵管可用性,数据分片找 Cluster——横向扩展的最后一讲,下一篇收官这个话题。

503

10 年全栈工程师 · 503咖啡馆主理人

#Sentinel#哨兵#故障转移#主观下线#客观下线#脑裂

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 5 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞