深蓝黑背景品牌封面:右侧大标题「failover 之后,数据会不会丢」,副标题「Redis 集群故障转移的一致性边界」;左侧原创装饰——主从两台服务器方块,主机向从机画一条异步复制虚线,主机方块上方一道闪电形故障标记,虚线中段一小段缺口寓意「还没来得及复制就宕机」的丢失窗口;左上标注「经典题解析 · 缓存」,右上标注「Day 08 · 10-16」 图 1:本文封面,虚线上那段缺口就是本题的全部答案。

先说明属性:这是一篇经典题解析,题目出自本地历史面试资料,与任何公司的当前招聘无关。它有个陷阱式的标准反问:你以为 failover 是「无感切换」,面试官想知道你清不清楚切换瞬间可能丢掉了什么。

想象面试现场:「Redis 主节点宕机,从节点升主。客户端刚才写成功的数据还在吗?什么情况下会丢?能不能不丢?」

核心结论一句话

可能丢。Redis 集群从设计上就不承诺强一致——官方规格书写得很直白:集群使用异步复制,对已确认的写入只做尽力保留,通常存在一个很小的丢失窗口。故障转移丢不丢数据、丢多少,取决于三个边界:异步复制的追赶进度、网络分区的持续时长、以及你愿不愿意为 WAIT 付等待的账。

边界一:异步复制的丢失窗口。

写请求的成功路径是:主节点写进自己内存、回客户端 OK,然后才把写操作异步发给从节点。「回 OK」和「从节点收到」之间有时间差——如果主节点在这个窗口里宕机,从节点升主,这最后一段已确认的写就永久丢失了。窗口通常很小(毫秒级),但它不是零。规格书原话级别的表述:窗口在客户端处于少数派分区时会更大。

边界二:脑裂,分区期间写给旧主的全部丢弃。

更锋利的场景是网络分区:主节点没死,只是和多数派失联了。哨兵或集群在多数派一侧选出新主继续服务,而分区另一侧的旧主在失联期间可能仍在接受客户端写入。分区恢复时旧主被降级为从,并回滚到与新主一致——分区期间写给旧主的那些数据,全部丢弃。所以「主节点还活着」不等于「写给它的数据安全」,安全的第一性问题是:它此刻还在多数派里吗。

边界三:WAIT 能把窗口压到多小。

Redis 提供了 WAIT 命令:写操作之后调用,阻塞等待直到此前的写被指定数量的从节点确认才返回,超时时间可配,返回实际确认数,客户端要自己检查是否达标。它能把丢失窗口压到接近零——写已经在至少一台从节点落了地,升主时带上这份数据的概率大增。但两个代价必须一起说:一是延迟,每次写至少多等一个复制往返;二是官方文档自己的警告——WAIT 并不能让 Redis 变成强一致存储,它只是「提高真实世界的数据安全性」,因为 failover 选主是尽力而为,理论上仍可能丢失已同步的写。从节点不足时,WAIT 还会把写阻塞到超时。

风险结构图:三栏并排讲清 failover 可能丢什么。左栏丢失窗口——写请求先落在主节点内存,异步复制还没追上,主节点宕机、从节点升主,这最后一段写永久丢失。中栏脑裂——网络分区后旧主仍接受写入,哨兵选出新主,分区恢复时旧主降级并回滚,分区期间写给旧主的数据全部丢弃。右栏 WAIT 命令——要求写操作等待指定数量的从节点确认再返回,把丢失窗口压缩到接近零,代价是每次写多等至少一个往返、从节点不足时写被阻塞。底部结论:Redis 集群不承诺强一致;把缓存定位成「可丢失的加速层」,要当准存储用就必须为丢失窗口付 WAIT 或外部队列的账 图 2:丢失窗口、脑裂与 WAIT,三个一致性边界。

可能的追问与易错点。

「WAIT 1 是不是就安全了?」更安全,不是绝对安全:它保证写到达一台从节点,不保证 failover 恰好选中这台——尽管选主算法会优先挑数据最全的从节点,尽力而为四个字仍在。「有没有真正不丢的方案?」有,但不在 Redis 内部:关键写先落外部队列或数据库,缓存只存副本,丢了能回放重建——这是把「不丢」的责任从缓存层挪给存储层的架构决策。「脑裂能避免吗?」配置层面能缩小窗口:min-replicas 系列参数可以让从节点不足时主节点拒绝写入,宁可不可用也不收丢了没人知道的数据。易错点有二:一是把「从节点升主成功」当「数据零丢失」——升主成功只说明集群可用,不说明复制追平;二是以为 WAIT 是事务或强一致——它是概率优化,不是承诺。

回到面试现场,建议的答题节奏:先一句话给结论(可能丢,设计上就不承诺强一致),再按丢失窗口、脑裂、WAIT 三个边界展开,每个边界都连同一个代价,然后补一句 min-replicas 的配置级收窄,最后落到选型哲学——把 Redis 定位成「可丢失的加速层」还是「准存储」,决定了你要不要为丢失窗口付钱。AI 应用的推理结果缓存正站在这条分界线上:当加速层用,丢了重算就是;当准存储用,故障切换那天的资损与答非所问,都是错误假设的账单。

你们团队的 Redis 里,有没有「其实丢不起」却按缓存用的数据?欢迎聊聊。