🛒
你在跑 shop.example.com:Redis 已经加了副本,监控也配了自动切换。主节点突然挂了,Sentinel 很快选出新主,App 重新连上——可刚确认成功的那一笔购物车写入,新主上却没有。本文只回答一件事:异步复制与 Sentinel 自动切换各自承诺什么、不承诺什么,以及「写成功了」为何仍可能丢。
系列压力大致按这条阶梯长大(本篇在「主从 + Sentinel」这一层):
系列上一篇讲的是本机磁盘还剩什么(RDB / AOF 与丢失窗口);本文接着讲:主挂之后,副本与自动切换能不能保住你刚拿到的成功应答。缓存怎么跟数据库配合,是同站另一类问题,这里不展开。

加了副本,为什么写成功仍可能丢?

事故现场通常很像这样:App 对 master 写入购物车,命令返回成功;片刻后 master 宕机,Sentinel 把某台副本提升为新主;你再读,刚写下的键不见了。
先固定四个角色,后面整篇都围着它们转:
  • 你 / App:对当前 master 发写命令,等成功应答。
  • master(主节点):接受写入、改自己的内存,并把复制流推给副本。
  • replica(副本):跟随 master 的复制流;默认不决定你何时收到写成功。
  • Sentinel(哨兵):监控、投票、自动 failover(故障切换),并给客户端提供「现在谁是主」的配置发现——它不替你把未复制的写入变出来。
Redis 默认使用异步复制(asynchronous replication):master 在内存里完成写入并向客户端应答成功时,不会先等副本确认「我已经收到并应用了这笔写」。副本通常很快跟上,但中间永远存在一段「主已 ACK、副本尚未应用」的时间窗。主若正好在这段窗口里挂掉,提升上来的新主就可能没有那笔数据。
读这张图时抓住一点:客户端成功不等于副本已有。加副本解决的是「主挂了还有份内存可提升、读可以分担」,不是「每笔已成功的写都已在副本落稳」。

断线重连:何时只补缺口,何时整库重来?

副本与 master 之间的连接会断、会抖。重连时 Redis 尽量走 PSYNC(Partial Resynchronization,部分重同步):用复制 ID(replication ID)和复制偏移量(offset),再配合 master 上的复制积压缓冲区(replication backlog),只把断线期间缺的那段命令补回去。
补不回来时,就退化为全量重同步(full resynchronization):master 生成 RDB 快照发给副本,再跟上快照之后的增量流——代价更大,窗口也更长。
重连结果
大致条件
你看到的代价
部分重同步(PSYNC)
复制 ID 仍匹配;缺口落在 backlog 内
只补偏移量之间的命令
全量重同步
复制历史对不上;缺口超出 backlog;或其它无法部分续传的情况
RDB 快照 + 后续流;更重、更久
PSYNC 不消灭上一节的异步丢写窗口:它管的是「断线后怎么尽快对齐」,不是「主在 ACK 时是否已等副本」。backlog 配太小、断线太久,更容易整库重来——运维上要按流量与抖动现实估 backlog,而不是假设「有副本就永远增量」。

WAIT 能让你睡得更香吗?它承诺了什么?

若某类写入你更不能丢(例如关键 session、结算前购物车快照),可以在写成功之后再发 WAIT:它会阻塞当前客户端,直到至少 N 个副本确认已经收到此前的写,或等到超时。
它承诺的是:在超时前,尽量把「副本确认数」推高,从而缩小 failover 时丢掉已 ACK 写的真实概率。官方也写明:这在 Sentinel / Cluster 的故障切换场景里能改善现实安全性。
它不承诺的是:
  • 不把 Redis 变成强一致(strongly consistent)系统;
  • 不保证超时后「一定已经安全」——你必须检查 WAIT 返回的副本确认数是否大于或等于你要求的 N;
  • 不消除所有丢写路径(例如确认之后副本又挂、或切换选中了仍落后的节点等现实组合)。
⚠️
WAIT 是可选的同步确认台阶,不是分布式事务,也不是「写成功 = 永不可丢」。调用方把返回值当一等公民;把 WAIT 当成强一致开关,会在事故里误判。

无持久化的 master 自动拉起,为什么更危险?

系列上一篇已经钉过:无持久化时,进程没了,本机内存数据就没了。复制拓扑里还有更狠的一跳。
官方在复制文档里强烈提醒:若 master 没有持久化,又被自动重启成一个空实例,而副本随后向这份「空主」同步,副本上原来还在的数据可能被冲成空库。也就是说:你以为「至少副本还活着」,结果空主一归队,把幸存副本一起拖下水。
官方建议很直接:给 Redis 打开持久化;或者不要让无持久化的实例在崩溃后自动拉起就继续当可同步的 master。Sentinel 解决的是「谁来当主」;它不自动修复「空主被当成权威数据源」这种配置事故。
这和「本机 RDB/AOF 丢几秒」差在哪?
本机持久化讨论的是:单进程崩溃后,磁盘上还能装回多少。空主陷阱讨论的是:复制拓扑里,一份错误的权威空数据集,通过同步把别的节点也清空。两层都要管;只开 Sentinel、却让无持久化 master 自动归队,危险面更大。

只要自动切换、数据还装得进一台:为什么是 Sentinel?

当你的问题是「单分片数据还装得进一台机器,但主挂了要自动切、客户端要知道新主在哪」,官方给出的非 Cluster 答案是 Redis Sentinel。
Sentinel 提供四件事(官方能力清单):
  1. 监控(monitoring):Sentinel 是否觉得实例按预期在工作。
  1. 通知(notification):可通过 API 把事件推给管理员或其他程序。
  1. 自动故障切换(automatic failover):主不可用时,把副本提升为新主,并让其它副本跟随新主。
  1. 配置提供者(configuration provider):客户端问 Sentinel「当前 master 是谁」,而不是把地址写死在配置文件里。
部署上,官方要求:至少 3 个 Sentinel,并放进独立的故障域(不要三个进程挤在同一台机、同一电源、同一网络故障点上「看起来有三票」)。客户端也必须真正支持 Sentinel 发现,而不是 failover 后仍死盯旧 IP。
Sentinel 做不到的事也要说清:它不做哈希槽分片,不把单机内存上限变没;异步复制下,已向客户端确认的写仍可能在切换后丢失——这与上一节同一因果链。

SDOWN 到切换成功,中间谁说了算?

自动切换不是「任意一个 Sentinel 觉得挂了就立刻切」。官方把主观与客观分开:
  • SDOWN(Subjectively Down,主观下线):单个 Sentinel 自己认为实例不可达。
  • ODOWN(Objectively Down,客观下线):达到配置的 quorum(法定人数)——足够多的 Sentinel 同意「master 真的不行了」——之后,才把 master 标成客观下线。
quorum 回答的是:「多少 Sentinel 同意不可达,才把 master 标成 ODOWN」。真正授权并完成 failover,还需要 Sentinel 集合里能够形成多数派(majority);若只有少数 Sentinel 活在一个网络分区里,它们不应擅自完成切换——否则脑裂风险会反噬你。
因此:监控可以敏感,切换必须「够多人同意」。配 2 个 Sentinel「凑合用」,既不满足官方至少 3 个的独立故障域建议,也容易在分区里失去可靠的多数判断。
Docker / NAT 下 Sentinel 为什么特别容易踩坑?
官方 Sentinel 文档提醒:在 Docker、NAT 或地址翻译环境里,Sentinel 与 Redis 互相宣告的 IP/端口可能和客户端真实可达地址不一致。结果是「Sentinel 内部觉得切成功了」,App 却连错地址或连到不可达端口。部署前先核对:Sentinel 发布的 master 地址,是否就是客户端网络里可达的那一个。

什么时候不该停在 Sentinel,而要走向 Cluster?

Sentinel 适合:还要自动切换,且整库数据与负载仍装得进单个 master(单分片心智),并接受「全键操作仍在一个主上」的模型。
当你的压力变成「一台的内存 / 写入打满了,必须水平切开键空间」,就该走向 Redis Cluster(集群):用固定哈希槽把键分散到多个主节点。选型可以收成下面这张决策图:
Cluster 不是「Sentinel 加强版」:它换的是数据面拓扑(多主分片),不是把异步复制改成强一致。下一篇会专门讲槽怎么切、客户端如何纠正路由;本文只帮你判断:什么时候不该再假装一台永远够用。

因果收束

你写入 → master 内存先改并应答 → 复制流异步追副本(默认不等待)→ 主在「未送达窗口」挂掉,新主可能没有刚 ACK 的写 → WAIT 只提高副本确认数、不是强一致 → 无持久化空主自动归队可能拖死副本 → Sentinel(至少 3 个、独立故障域、客户端感知)负责单分片监控与切主,ODOWN 看 quorum、真正切换还要 Sentinel 多数 → 单机装不下再上 Cluster。
默认复制是异步的:成功应答不等于副本已应用。
关键写入评估 WAIT,并检查返回的确认数大于或等于要求的 N。
master 打开持久化;避免无持久化实例崩溃后自动当空主再同步。
Sentinel 至少 3 个,放进独立故障域;客户端用 Sentinel 发现当前 master。
理解 quorum(客观下线)与多数派(真正 failover)不是同一句话。
数据仍单分片装得下 → Sentinel;必须水平切开 → Cluster(下一篇)。
范围外:托管云控制台专有行为、把本站应用缓存客户端当成服务端机制证明。
主挂可以自动切;刚成功的写,仍可能停在「未送达」的那一段复制延迟里。
来源与更深阅读
证据复核日期:2026-08-15。
复制(默认异步、PSYNC / 全量重同步、无持久化空主风险、WAIT 作为可选确认):https://redis.io/docs/latest/operate/oss_and_stack/management/replication/
WAIT 命令(阻塞至 N 个副本确认或超时;非强一致;须检查返回值):https://redis.io/docs/latest/commands/wait/
Sentinel(非 Cluster 的 HA:监控、通知、自动 failover、配置发现;至少 3 个与故障域;quorum;异步复制下已确认写仍可能丢):https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel/
系列上一篇(本机 RDB/AOF):https://ximouzhao.com/article/redis-persistence-rdb-aof
系列下一篇预告:Redis Cluster 哈希槽与水平扩展(分片、路由纠正与部署形态),不在本文展开。
Redis 扩容靠的不是一致性哈希:16384 个槽如何托住水平扩展?进程被 kill 之后,Redis 里还剩什么?
Loading...