redis主从切换丢数据的根本原因是持久化与复制偏移量不同步:save阻塞、bgsave fork后新写入未落盘、repl-backlog过小导致断层;aof应选everysec,repl-backlog需按qps×大小×断连时间预估并设为永不清空,min-slaves-to-write和max-lag是防脑裂底线。

Redis 在主从切换期间可能丢失未落盘的数据,根本原因不是“选主慢”,而是持久化策略与复制偏移量不同步——save 阻塞、bgsave 进程竞争、以及 repl-backlog 容量不足共同导致数据断层。
为什么 save 和 bgsave 在故障窗口期不可靠
主节点宕机前若正执行 bgsave,子进程只拷贝 fork 时刻的内存快照;而 fork 后新写入的命令若还没来得及写入 aof 或下一次 bgsave,就会永久丢失。更危险的是:若配置了 save 900 1 这类低频触发规则,主挂掉前可能压根没触发过任何落盘。
-
save是同步阻塞操作,绝不能在主节点高负载或主从切换前手动调用 -
bgsave依赖 fork,而大内存实例 fork 耗时长(百毫秒级),期间新增写入无法被本次快照捕获 - 默认
stop-writes-on-bgsave-error yes会让写入失败,但错误日志容易被忽略,实际已静默丢数据
aof 的 appendfsync 策略怎么选才扛住切换
选 no 就是把落盘交给 OS 缓冲区,主挂掉时可能丢几秒数据;选 always 虽然安全但性能暴跌(每次写都 fsync);真正平衡点是 everysec——但要注意它不是“每秒刷一次”,而是「主线程把命令写入缓冲区后立即返回,后台线程每秒 fsync 一次」,所以最坏情况丢 1 秒数据。
- 必须关闭
aof-rewrite-incremental-fsync yes,否则 AOF 重写期间 fsync 会退化为随机小写,放大延迟抖动 - 若使用 SSD,可将
aof-dir和dbfilename放在单独挂载点,避免与系统日志争 I/O -
aof-use-rdb-preamble yes开启后,AOF 文件开头是 RDB 格式,能加速加载,但重写时仍需完整解析旧 AOF,不降低风险
主从切换时 repl-backlog 不够大,从库变主库就丢数据
哨兵或集群选主后,新主库如果之前是旧主的从库,它要靠 repl-backlog(环形缓冲区)补全断连期间的命令。但默认只有 1MB,千兆网卡上撑不过 2 秒——一旦网络抖动超时或从库重启,PSYNC 就降级为 FULLRESYNC,触发全量同步,期间所有增量写入全部丢失。
- 按写入 QPS × 命令平均大小 × 预期最大断连时间估算,例如 5k QPS × 100B × 60s = 30MB,
repl-backlog-size至少设为32mb -
repl-backlog-ttl默认 60 秒,指缓冲区空闲多久后自动释放,线上应设为 0(永不清空) - 从库升级为主库后,它的
repl-backlog不会自动清空,但旧主恢复为从库时会重新申请,所以 backlog 大小必须全局一致
哨兵模式下 min-slaves-to-write 和 min-slaves-max-lag 是保命开关
这两个配置不是“提升可用性”的锦上添花项,而是“防止脑裂丢数据”的底线控制。当从库全部掉线或延迟超标时,强制主库拒绝写入,宁可报错也不能让数据只存在单点内存里。
-
min-slaves-to-write 1意味着只要有一个从库在线就允许写,太冒险;建议设为2(一主两从架构下) -
min-slaves-max-lag 10表示从库延迟不能超过 10 秒,否则主库停写——注意这个值必须小于repl-backlog-size能覆盖的时间窗 - 这两个参数只对主库生效,从库不会继承,必须在每个主节点上显式配置
真正难处理的不是配置本身,而是当 repl-backlog 覆盖不了网络分区时长、又没开 min-slaves-to-write,此时无论 AOF 多严谨,数据已在主库内存里蒸发了——监控得盯住 instantaneous_ops_per_sec 和 slave_repl_offset 的差值,而不是等哨兵发告警才反应。










