Redis 真正进入高可用阶段时,不能把“复制”和“自动故障转移”分成两段完全独立的知识。复制负责让副本追上主库,Sentinel 负责在主库故障后判断是否切换、由谁切换、切到哪个副本,以及客户端应当去哪里找新主库。

系列导航:

复制先解决“副本怎么追上主库”

一个最基础的 Redis 高可用拓扑,至少有一个主库和一个副本:

应用写入


主库
   │  异步复制流

副本

主库处理写命令,副本接收并重放复制流。它解决的是“多一份近实时副本”的问题,但它本身并不负责:

  • 主库故障后的自动提升。
  • 客户端写入口自动切换。
  • 故障时零数据丢失。

所以“已经有副本”和“系统已经高可用”之间,还差一整个控制平面。

全量同步、部分重同步和复制积压缓冲区

理解 Redis 复制,最关键的是三件事:replication ID、复制偏移量和复制积压缓冲区。

  • replication ID 用来标识当前复制历史。
  • 复制偏移量用来标识复制流推进到了哪里。
  • 积压缓冲区保存最近一段复制流,给短暂断线后的副本做续传。

首次建立复制关系时,副本通常要做一次全量同步:

  1. 副本发送 PSYNC
  2. 主库判断当前没有可复用的复制历史。
  3. 主库准备 RDB 快照,同时把后续写命令暂存起来。
  4. 副本加载快照。
  5. 主库把快照期间积累的写命令补发给副本。
  6. 两端进入持续复制阶段。

如果副本只是短暂断线,重连时会带上自己记录的 replication ID 和偏移量。只要主库确认复制历史没变,而且缺失那段复制流还在积压缓冲区里,就可以做部分重同步,只发送断线期间缺失的部分,而不需要重新传整份数据集。

这也是 repl-backlog-size 真正该按业务写入速率来估算的原因。它不是越大越高级,而是要覆盖你希望副本可以容忍的断线时间窗口。

Redis 复制一直是异步复制

复制链路最重要的边界,是它默认不会把“副本已经确认收到”作为主库给客户端返回成功的前提。

这会形成一个很现实的风险窗口:

客户端收到写入成功

      ├─ 主库已执行
      └─ 副本尚未收到

如果此时主库故障,而新的写主又从副本里选出来,那么这段还没来得及复制过去的写入就可能丢失。WAIT 能让单个客户端在当前连接上等待一定数量副本确认偏移量,但它不是把 Redis 复制改造成强一致协议,也不能替代完整的故障域设计和持久化设计。

因此,Redis 复制解决的是“尽快把数据传播到副本”,不是“任何故障下都严格不丢数据”。

Sentinel 负责把复制链路变成自动故障转移闭环

有了复制以后,系统仍然要回答四个控制面问题:

  1. 主库是真的故障了,还是某个节点自己的网络抖动?
  2. 由哪个 Sentinel 来主持这一轮故障转移?
  3. 哪个副本最适合被提升成新主库?
  4. 客户端之后应该去哪里找新的主库地址?

Sentinel 的职责正好覆盖这些点:

  • 监控主库、副本和其他 Sentinel 的可达性。
  • 通过逻辑主库名做服务发现。
  • 在满足条件时协调故障转移。
  • 在切换完成后把新主库信息暴露给客户端。

它不保存业务数据,也不代理 Redis 请求。应用最终还是直接连 Redis,只是在建立连接或故障恢复时,先向 Sentinel 查询“当前主库是谁”。

SDOWN、ODOWN、quorum 和多数派不是一回事

Sentinel 不会因为一个节点单方面超时就立刻提升副本。它把故障判断分成两层:

  • SDOWN:某个 Sentinel 在自己的视角里,连续一段时间联系不到主库。
  • ODOWN:达到配置的 quorum 后,多个 Sentinel 对主库故障形成客观判断。

但形成 ODOWN 还不等于能立刻执行故障转移。因为还要再解决一个问题:谁来主持这一轮切换。这个时候依赖的是 Sentinel 多数派授权,而不是单纯的 quorum

可以把两者记成:

  • quorum 决定“大家是否同意主库可能真的坏了”。
  • 多数派决定“谁有权在这一轮真正动手切换”。

这也是为什么三 Sentinel、quorum 2 是最常见的最小可用拓扑。一台 Sentinel 失联时,剩余两台仍有机会完成判断和授权;只剩一台时,即使它看得到副本,也不应该独自完成自动故障转移。

Sentinel 会怎么选出新主库

当某个 Sentinel 获得本轮多数派授权后,它会从可晋升的副本里挑一个最适合成为新主库的候选者。筛选时通常会考虑:

  1. replica-priority,值越小优先级越高,0 表示不参与晋升。
  2. 副本复制偏移量是否足够新,谁离旧主库最近。
  3. 运行 ID 等稳定排序字段,用于在条件接近时打破平局。

然后故障转移大致按下面的顺序推进:

  1. 把目标副本提升为新主库。
  2. 等待它角色切换生效。
  3. 让其他副本转向跟随新主库。
  4. 更新 Sentinel 内部维护的主库地址和纪元信息。
  5. 对外返回新的主库发现结果。
  6. 旧主库恢复后,将其收编为当前主库的副本。

你可以把整条链路理解成:复制提供数据连续性,Sentinel 提供角色重组和写入口切换能力。两者合在一起,才构成单主 Redis 的自动故障转移闭环。

客户端真正接入时要注意什么

Sentinel 成功切换,不代表应用就会自动跟上。要真正完成闭环,还要满足三个前提:

  • 客户端支持 Sentinel 模式,并配置多个 Sentinel 地址与逻辑主库名。
  • 应用没有把旧主库地址硬编码在配置里。
  • 连接池、重连策略和认证信息能在主库切换后正确更新。

实际排查时,最常用的两个入口通常是:

redis-cli INFO replication
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster

前者看主库、副本和复制偏移量,后者看 Sentinel 当前认定的写入口。只盯其中一边,很容易误判“复制明明正常,为什么业务还是没恢复”。

一条够用的线上检查清单

如果你希望把 Redis 单主高可用看得更稳,至少要固定检查下面这些问题:

  1. 副本是否真的能在短暂断线后做部分重同步,而不是频繁退回全量同步。
  2. 积压缓冲区大小是否匹配写入速率和网络波动窗口。
  3. Sentinel 的 quorum 和部署位置是否避开同一故障域。
  4. 客户端是否真的通过 Sentinel 做主库发现,而不是只在文档里“支持”。
  5. 业务是否清楚接受异步复制下的丢失窗口边界。
  6. 旧主库恢复后是否有明确的重新纳管流程,而不是直接重新放流量。

把这些动作固定下来以后,“Redis 高可用”才不只是“我已经有副本,也已经起了几个 Sentinel”的表面状态。

本篇解决了什么:

  • 把全量同步、部分重同步、复制积压和异步复制边界串成了一条链路
  • 解释了 SDOWNODOWNquorum 和多数派授权在自动切换里各自负责什么
  • 让复制与 Sentinel 不再拆成两篇独立拼图,而是形成完整高可用闭环

下一篇:Redis Cluster:哈希槽、重定向与分片扩展(十)