这是redis 2.8至3.2的已知bug,主节点全量同步时将实时offset误写入rdb头,致从节点加载后offset虚高,引发增量同步失败;4.0起psync2通过rdb存replication id与精确offset、原子校验backlog修复该问题。

主从切换后slave的offset突然比master还大?这是2.8/3.2的已知BUG
不是配置错了,也不是网络抖动导致的临时错乱——这是Redis 2.8到3.2版本中一个被长期忽略的全量同步逻辑缺陷。当主从因网络中断触发FULLRESYNC时,主节点在发送+FULLRESYNC响应前,会错误地把「当前实时offset」而非「bgsave开始时刻的offset」写入RDB文件头。从节点加载RDB后,就拿到了一个虚高的初始offset,后续增量同步必然失败,最终表现为slave_repl_offset > master_repl_offset。
这个BUG在2015年TOR故障事件中大规模暴露,但直到4.0才被彻底修复。如果你还在用3.2或更早版本,即使哨兵切换成功、客户端连上新主,只要发生过一次全量同步,就可能埋下数据不一致隐患。
升级到Redis 4.0+后,PSYNC2如何保证offset连续性
4.0引入的PSYNC2不只是协议升级,它重构了offset生成和持久化路径:
- RDB文件头不再只存run_id,而是明确记录
replication ID和replication offset两个字段,且该offset严格对应bgsave启动瞬间的主节点状态 - 从节点重启或重连时,会优先从RDB中读取这两个值作为PSYNC请求参数,而不是靠自己猜或靠主节点“给”
- 主节点在处理PSYNC请求时,不再简单比对run_id,而是先检查请求中的offset是否落在
repl_backlog窗口内——这个判断是原子的、可验证的
这意味着:哪怕你手动执行SLAVEOF NO ONE再SLAVEOF回原主,只要RDB没被覆盖、backlog没清空,offset就能接续上。不用再担心“切一次丢一段增量”。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
升级后必须改的三项配置,否则PSYNC2形同虚设
光升级不行,旧版默认配置会直接让PSYNC2退化成PSYNC1:
-
repl-backlog-size:默认1mb,对QPS>5k的实例,30秒断连就溢出。按峰值写入带宽 × 60s估算,建议至少设为64mb -
repl-backlog-ttl:默认3600秒,但哨兵切换期间若无从节点连接,backlog会被清空。生产环境应设为0(永不过期) -
repl-diskless-sync:设为yes,避免RDB落盘IO阻塞,否则全量同步耗时翻倍,增大offset追平窗口
改完记得CONFIG REWRITE并重启,否则INFO replication里看不到repl_backlog_active:1。
验证升级是否真正生效的关键检查点
别只看redis-server --version,重点查运行时行为:
- 连上从节点,执行
redis-cli info replication | grep -E "(role|master_link_status|slave_repl_offset)",确认role:slave且master_link_status:up - 连上主节点,执行
redis-cli info replication | grep -E "(master_repl_offset|repl_backlog_histlen|repl_backlog_size)",确认repl_backlog_histlen接近repl_backlog_size(说明backlog在持续写入) - 模拟一次网络断连:在从节点执行
redis-cli client kill type slave,等10秒后再观察slave_repl_offset是否继续增长——如果它停在某个值不动,说明PSYNC2没走通,大概率是backlog太小或repl-backlog-ttl过早清空
最隐蔽的坑是:升级后所有命令都正常返回,INFO看起来也健康,但一旦真实断连,就立刻退化为全量同步。这种问题不会报错,只会悄悄拖慢集群恢复速度、放大脑裂风险。










